• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

yuce / pyswip / 11425971712

20 Oct 2024 11:34AM UTC coverage: 82.772%. Remained the same
11425971712

push

github

web-flow
Added initial docs (#180)

Added initial docs

1057 of 1277 relevant lines covered (82.77%)

4.9 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.86
/src/pyswip/core.py
1
# Copyright (c) 2007-2024 Yüce Tekol and PySwip Contributors
2
#
3
# Permission is hereby granted, free of charge, to any person obtaining a copy
4
# of this software and associated documentation files (the "Software"), to deal
5
# in the Software without restriction, including without limitation the rights
6
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
# copies of the Software, and to permit persons to whom the Software is
8
# furnished to do so, subject to the following conditions:
9
#
10
# The above copyright notice and this permission notice shall be included in all
11
# copies or substantial portions of the Software.
12
#
13
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
# SOFTWARE.
20

21
import atexit
6✔
22
import glob
6✔
23
import os
6✔
24
import sys
6✔
25
from contextlib import contextmanager
6✔
26
from ctypes import *
6✔
27
from ctypes.util import find_library
6✔
28
from subprocess import Popen, PIPE
6✔
29
from typing import Tuple
6✔
30

31
ENV_LIBSWIPL_PATH = "LIBSWIPL_PATH"
6✔
32
ENV_SWI_HOME_DIR = "SWI_HOME_DIR"
6✔
33

34

35
class PySwipError(Exception):
6✔
36
    def __init__(self, message):
6✔
37
        super().__init__(message)
×
38

39

40
class SwiPrologNotFoundError(PySwipError):
6✔
41
    def __init__(self, message="SWI-Prolog not found"):
6✔
42
        super().__init__(message)
×
43

44

45
# To initialize the SWI-Prolog environment, two things need to be done: the
46
# first is to find where the SO/DLL is located and the second is to find the
47
# SWI-Prolog home, to get the saved state.
48
#
49
# The goal of the (entangled) process below is to make the library installation
50
# independent.
51

52

53
def _findSwiplPathFromFindLib():
6✔
54
    """
55
    This function resorts to ctype's find_library to find the path to the
56
    DLL. The biggest problem is that find_library does not give the path to the
57
    resource file.
58

59
    :returns:
60
        A path to the swipl SO/DLL or None if it is not found.
61

62
    :returns type:
63
        {str, None}
64
    """
65

66
    path = (
3✔
67
        find_library("swipl") or find_library("pl") or find_library("libswipl")
68
    )  # This last one is for Windows
69
    return path
3✔
70

71

72
def _findSwiplFromExec():
6✔
73
    """
74
    This function tries to use an executable on the path to find SWI-Prolog
75
    SO/DLL and the resource file.
76

77
    :returns:
78
        A tuple of (path to the swipl DLL, path to the resource file)
79

80
    :returns type:
81
        ({str, None}, {str, None})
82
    """
83

84
    platform = sys.platform[:3]
6✔
85

86
    fullName = None
6✔
87
    swiHome = None
6✔
88

89
    try:  # try to get library path from swipl executable.
6✔
90
        # We may have pl or swipl as the executable
91
        cmd = Popen(["swipl", "--dump-runtime-variables"], stdout=PIPE)
6✔
92
        ret = cmd.communicate()
6✔
93

94
        # Parse the output into a dictionary
95
        ret = ret[0].decode().replace(";", "").splitlines()
6✔
96
        ret = [line.split("=", 1) for line in ret]
6✔
97
        rtvars = dict((name, value[1:-1]) for name, value in ret)  # [1:-1] gets
6✔
98
        # rid of the
99
        # quotes
100

101
        if rtvars["PLSHARED"] == "no":
6✔
102
            raise ImportError("SWI-Prolog is not installed as a shared " "library.")
×
103
        else:  # PLSHARED == 'yes'
104
            swiHome = rtvars["PLBASE"]  # The environment is in PLBASE
6✔
105
            if not os.path.exists(swiHome):
6✔
106
                swiHome = None
×
107

108
            # determine platform specific path.  First try runtime
109
            # variable `PLLIBSWIPL` introduced in 9.1.1/9.0.1
110
            if "PLLIBSWIPL" in rtvars:
6✔
111
                fullName = rtvars["PLLIBSWIPL"]
3✔
112
            # determine platform specific path
113
            elif platform == "win":
3✔
114
                dllName = rtvars["PLLIB"][:-4] + "." + rtvars["PLSOEXT"]
×
115
                path = os.path.join(rtvars["PLBASE"], "bin")
×
116
                fullName = os.path.join(path, dllName)
×
117

118
                if not os.path.exists(fullName):
×
119
                    fullName = None
×
120

121
            elif platform == "cyg":
3✔
122
                # e.g. /usr/lib/pl-5.6.36/bin/i686-cygwin/cygpl.dll
123

124
                dllName = "cygpl.dll"
×
125
                path = os.path.join(rtvars["PLBASE"], "bin", rtvars["PLARCH"])
×
126
                fullName = os.path.join(path, dllName)
×
127

128
                if not os.path.exists(fullName):
×
129
                    fullName = None
×
130

131
            elif platform == "dar":
3✔
132
                dllName = "lib" + rtvars["PLLIB"][2:] + "." + "dylib"
×
133
                path = os.path.join(rtvars["PLBASE"], "lib", rtvars["PLARCH"])
×
134
                baseName = os.path.join(path, dllName)
×
135

136
                if os.path.exists(baseName):
×
137
                    fullName = baseName
×
138
                else:  # We will search for versions
139
                    fullName = None
×
140

141
            else:  # assume UNIX-like
142
                # The SO name in some linuxes is of the form libswipl.so.5.10.2,
143
                # so we have to use glob to find the correct one
144
                dllName = "lib" + rtvars["PLLIB"][2:] + "." + rtvars["PLSOEXT"]
3✔
145
                path = os.path.join(rtvars["PLBASE"], "lib", rtvars["PLARCH"])
3✔
146
                baseName = os.path.join(path, dllName)
3✔
147

148
                if os.path.exists(baseName):
3✔
149
                    fullName = baseName
×
150
                else:  # We will search for versions
151
                    pattern = baseName + ".*"
3✔
152
                    files = glob.glob(pattern)
3✔
153
                    if len(files) == 0:
3✔
154
                        fullName = None
3✔
155
                    else:
156
                        fullName = files[0]
×
157

158
    except (OSError, KeyError):  # KeyError from accessing rtvars
×
159
        pass
×
160

161
    return fullName, swiHome
6✔
162

163

164
def _find_swipl_windows():
6✔
165
    """
166
    This function uses several heuristics to gues where SWI-Prolog is installed
167
    in Windows.
168

169
    :returns:
170
        A tuple of (path to the swipl DLL, path to the resource file)
171

172
    :returns type:
173
        ({str, None}, {str, None})
174
    """
175

176
    libswipl = "libswipl.dll"
×
177
    # tru to get the SWI dir from registry
178
    swi_dir = find_swipl_dir_from_registry()
×
179
    if swi_dir:
×
180
        # libswipl.dll must be in SWI_DIR/bin
181
        libswipl_path = os.path.join(swi_dir, "bin", libswipl)
×
182
        if not os.path.exists(libswipl_path):
×
183
            raise SwiPrologNotFoundError(
×
184
                f"could not locate {libswipl} at {libswipl_path}"
185
            )
186
        return libswipl_path, swi_dir
×
187

188
    raise SwiPrologNotFoundError
×
189

190

191
def find_swipl_dir_from_registry():
6✔
192
    import winreg
×
193

194
    try:
×
195
        with winreg.OpenKeyEx(winreg.HKEY_LOCAL_MACHINE, r"Software\SWI\Prolog") as key:
×
196
            path, _ = winreg.QueryValueEx(key, "home")
×
197
            return path
×
198
    except FileNotFoundError:
×
199
        return ""
×
200

201

202
def _find_swipl_unix():
6✔
203
    """
204
    This function uses several heuristics to guess where SWI-Prolog is
205
    installed in Linuxes.
206

207
    :returns:
208
        A tuple of (path to the swipl so, path to the resource file)
209

210
    :returns type:
211
        ({str, None}, {str, None})
212
    """
213

214
    # Maybe the exec is on path?
215
    path, swi_home = _findSwiplFromExec()
6✔
216
    if path is not None:
6✔
217
        return path, swi_home
3✔
218

219
    # If it is not, use  find_library
220
    path = _findSwiplPathFromFindLib()
3✔
221
    if path is not None:
3✔
222
        swi_home = find_swi_home(path)
3✔
223
        return path, swi_home
3✔
224

225
    # Our last try: some hardcoded paths.
226
    paths = [
×
227
        "/lib",
228
        "/usr/lib",
229
        "/usr/local/lib",
230
        ".",
231
        "./lib",
232
        "/usr/lib/swi-prolog/lib/x86_64-linux",
233
    ]
234
    names = ["libswipl.so"]
×
235

236
    path = None
×
237
    for name in names:
×
238
        for try_ in paths:
×
239
            try_ = os.path.join(try_, name)
×
240
            if os.path.exists(try_):
×
241
                path = try_
×
242
                break
×
243

244
    if path is not None:
×
245
        swi_home = find_swi_home(path)
×
246
        return path, swi_home
×
247

248
    raise SwiPrologNotFoundError
×
249

250

251
def find_swipl_macos_home() -> Tuple[str, str]:
6✔
252
    """
253
    This function is guesing where SWI-Prolog is
254
    installed in MacOS via .app.
255

256
    :parameters:
257
      -  `swi_ver` (str) - Version of SWI-Prolog in '[0-9].[0-9].[0-9]' format
258

259
    :returns:
260
        A tuple of (path to the swipl so, path to the resource file)
261

262
    :returns type:
263
        ({str, None}, {str, None})
264
    """
265

266
    swi_home = os.environ.get("SWI_HOME_DIR")
×
267
    if not swi_home:
×
268
        swi_home = "/Applications/SWI-Prolog.app/Contents/swipl"
×
269
    if os.path.exists(swi_home):
×
270
        swi_base = os.path.split(swi_home)[0]
×
271
        framework_path = os.path.join(swi_base, "Frameworks")
×
272
        lib = find_swipl_dylib(framework_path)
×
273
        if lib:
×
274
            lib_path = os.path.join(framework_path, lib)
×
275
            return lib_path, swi_home
×
276

277
    return "", ""
×
278

279

280
def find_swipl_dylib(root) -> str:
6✔
281
    for item in os.listdir(root):
×
282
        if item.startswith("libswipl") and item.endswith(".dylib"):
×
283
            return item
×
284
    return ""
×
285

286

287
def _find_swipl_darwin() -> (str, str):
6✔
288
    """
289
    This function uses several heuristics to guess where SWI-Prolog is
290
    installed in MacOS.
291

292
    :returns:
293
        A tuple of (path to the swipl so, path to the resource file)
294

295
    :returns type:
296
        ({str, None}, {str, None})
297
    """
298

299
    path, swi_home = find_swipl_macos_home()
×
300
    if path and swi_home:
×
301
        return path, swi_home
×
302

303
    # If the exec is in path
304
    path, swi_home = _findSwiplFromExec()
×
305
    if path:
×
306
        return path, swi_home
×
307

308
    # If it is not, use  find_library
309
    path = _findSwiplPathFromFindLib()
×
310
    if path:
×
311
        swi_home = find_swi_home(os.path.dirname(path))
×
312
        return path, swi_home
×
313

314
    raise SwiPrologNotFoundError
×
315

316

317
def find_swi_home(path) -> str:
6✔
318
    while True:
2✔
319
        swi_home = os.path.join(path, "swipl.home")
3✔
320
        if os.path.exists(swi_home):
3✔
321
            with open(swi_home) as f:
×
322
                sub_path = f.read().strip()
×
323
                return os.path.join(path, sub_path)
×
324
        path, leaf = os.path.split(path)
3✔
325
        if not leaf:
3✔
326
            break
3✔
327
    return ""
3✔
328

329

330
def _find_swipl() -> (str, str):
6✔
331
    """
332
    This function makes a big effort to find the path to the SWI-Prolog shared
333
    library. Since this is both OS dependent and installation dependent, we may
334
    not aways succeed. If we do, we return a name/path that can be used by
335
    CDLL(). Otherwise we raise an exception.
336

337
    :return: Tuple. Fist element is the name or path to the library that can be
338
             used by CDLL. Second element is the path were SWI-Prolog resource
339
             file may be found (this is needed in some Linuxes)
340
    :rtype: Tuple of strings
341
    :raises ImportError: If we cannot guess the name of the library
342
    """
343
    # Check the environment first
344
    libswipl_path = os.environ.get(ENV_LIBSWIPL_PATH)
6✔
345
    swi_home_dir = os.environ.get(ENV_SWI_HOME_DIR)
6✔
346
    if libswipl_path and swi_home_dir:
6✔
347
        return libswipl_path, swi_home_dir
×
348

349
    # Now begins the guesswork
350
    platform = sys.platform
6✔
351
    if platform == "win32":
6✔
352
        libswipl_path, swi_home_dir = _find_swipl_windows()
×
353
        fix_windows_path(libswipl_path)
×
354
        return libswipl_path, swi_home_dir
×
355
    elif platform == "darwin":
6✔
356
        return _find_swipl_darwin()
×
357
    else:
358
        # This should work for other Linux and BSD
359
        return _find_swipl_unix()
6✔
360

361

362
def fix_windows_path(dll):
6✔
363
    """
364
    When the path to the DLL is not in Windows search path, Windows will not be
365
    able to find other DLLs on the same directory, so we have to add it to the
366
    path. This function takes care of it.
367

368
    :parameters:
369
      -  `dll` (str) - File name of the DLL
370
    """
371

372
    pathToDll = os.path.dirname(dll)
×
373
    currentWindowsPath = os.getenv("PATH")
×
374

375
    if pathToDll not in currentWindowsPath:
×
376
        # We will prepend the path, to avoid conflicts between DLLs
377
        newPath = pathToDll + ";" + currentWindowsPath
×
378
        os.putenv("PATH", newPath)
×
379

380

381
_stringMap = {}
6✔
382

383

384
def str_to_bytes(string):
6✔
385
    """
386
    Turns a string into a bytes if necessary (i.e. if it is not already a bytes
387
    object or None).
388
    If string is None, int or c_char_p it will be returned directly.
389

390
    :param string: The string that shall be transformed
391
    :type string: str, bytes or type(None)
392
    :return: Transformed string
393
    :rtype: c_char_p compatible object (bytes, c_char_p, int or None)
394
    """
395
    if string is None or isinstance(string, (int, c_char_p)):
6✔
396
        return string
6✔
397

398
    if not isinstance(string, bytes):
6✔
399
        if string not in _stringMap:
6✔
400
            _stringMap[string] = string.encode()
6✔
401
        string = _stringMap[string]
6✔
402

403
    return string
6✔
404

405

406
def list_to_bytes_list(strList):
6✔
407
    """
408
    This function turns an array of strings into a pointer array
409
    with pointers pointing to the encodings of those strings
410
    Possibly contained bytes are kept as they are.
411

412
    :param strList: List of strings that shall be converted
413
    :type strList: List of strings
414
    :returns: Pointer array with pointers pointing to bytes
415
    :raises: TypeError if strList is not list, set or tuple
416
    """
417
    pList = c_char_p * len(strList)
6✔
418

419
    # if strList is already a pointerarray or None, there is nothing to do
420
    if isinstance(strList, (pList, type(None))):
6✔
421
        return strList
×
422

423
    if not isinstance(strList, (list, set, tuple)):
6✔
424
        raise TypeError("strList must be list, set or tuple, not " + str(type(strList)))
×
425

426
    pList = pList()
6✔
427
    for i, elem in enumerate(strList):
6✔
428
        pList[i] = str_to_bytes(elem)
6✔
429
    return pList
6✔
430

431

432
# create a decorator that turns the incoming strings into c_char_p compatible
433
# butes or pointer arrays
434
def check_strings(strings, arrays):
6✔
435
    """
436
    Decorator function which can be used to automatically turn an incoming
437
    string into a bytes object and an incoming list to a pointer array if
438
    necessary.
439

440
    :param strings: Indices of the arguments must be pointers to bytes
441
    :type strings: List of integers
442
    :param arrays: Indices of the arguments must be arrays of pointers to bytes
443
    :type arrays: List of integers
444
    """
445

446
    # if given a single element, turn it into a list
447
    if isinstance(strings, int):
6✔
448
        strings = [strings]
6✔
449
    elif strings is None:
6✔
450
        strings = []
6✔
451

452
    # check if all entries are integers
453
    for i, k in enumerate(strings):
6✔
454
        if not isinstance(k, int):
6✔
455
            raise TypeError(
×
456
                (
457
                    "Wrong type for index at {0} " + "in strings. Must be int, not {1}!"
458
                ).format(i, k)
459
            )
460

461
    # if given a single element, turn it into a list
462
    if isinstance(arrays, int):
6✔
463
        arrays = [arrays]
6✔
464
    elif arrays is None:
6✔
465
        arrays = []
6✔
466

467
    # check if all entries are integers
468
    for i, k in enumerate(arrays):
6✔
469
        if not isinstance(k, int):
6✔
470
            raise TypeError(
×
471
                (
472
                    "Wrong type for index at {0} " + "in arrays. Must be int, not {1}!"
473
                ).format(i, k)
474
            )
475

476
    # check if some index occurs in both
477
    if set(strings).intersection(arrays):
6✔
478
        raise ValueError(
×
479
            "One or more elements occur in both arrays and "
480
            + " strings. One parameter cannot be both list and string!"
481
        )
482

483
    # create the checker that will check all arguments given by argsToCheck
484
    # and turn them into the right datatype.
485
    def checker(func):
6✔
486
        def check_and_call(*args):
6✔
487
            args = list(args)
6✔
488
            for i in strings:
6✔
489
                arg = args[i]
6✔
490
                args[i] = str_to_bytes(arg)
6✔
491
            for i in arrays:
6✔
492
                arg = args[i]
6✔
493
                args[i] = list_to_bytes_list(arg)
6✔
494

495
            return func(*args)
6✔
496

497
        return check_and_call
6✔
498

499
    return checker
6✔
500

501

502
# Find the path and resource file. SWI_HOME_DIR shall be treated as a constant
503
# by users of this module
504
_path, SWI_HOME_DIR = _find_swipl()
6✔
505

506
# Load the library
507
_lib = CDLL(_path, mode=RTLD_GLOBAL)
6✔
508

509
#       /*******************************
510
#        *              VERSIONS                *
511
#        *******************************/
512

513
PL_VERSION_SYSTEM = 1  # Prolog version
6✔
514
PL_VERSION_FLI = 2  # PL_* compatibility
6✔
515
PL_VERSION_REC = 3  # PL_record_external() compatibility
6✔
516
PL_VERSION_QLF = 4  # Saved QLF format version
6✔
517
PL_VERSION_QLF_LOAD = 5  # Min loadable QLF format version
6✔
518
PL_VERSION_VM = 6  # VM signature
6✔
519
PL_VERSION_BUILT_IN = 7  # Built-in predicate signature
6✔
520

521
# After SWI-Prolog 8.5.2, PL_version was renamed to PL_version_info
522
# to avoid a conflict with Perl. For more details, see the following:
523
# https://github.com/SWI-Prolog/swipl-devel/issues/900
524
# https://github.com/SWI-Prolog/swipl-devel/issues/910
525
try:
6✔
526
    if hasattr(_lib, "PL_version_info"):
6✔
527
        PL_version = _lib.PL_version_info  # swi-prolog > 8.5.2
3✔
528
    else:
529
        PL_version = _lib.PL_version  # swi-prolog <= 8.5.2
3✔
530
    PL_version.argtypes = [c_int]
6✔
531
    PL_version.restype = c_uint
6✔
532

533
    PL_VERSION = PL_version(PL_VERSION_SYSTEM)
6✔
534
    if PL_VERSION < 80200:
6✔
535
        raise Exception("swi-prolog >= 8.2.0 is required")
×
536
except AttributeError:
×
537
    raise Exception("swi-prolog version number could not be determined")
×
538

539
# PySwip constants
540
PYSWIP_MAXSTR = 1024
6✔
541
c_int_p = c_void_p
6✔
542
c_long_p = c_void_p
6✔
543
c_double_p = c_void_p
6✔
544
c_uint_p = c_void_p
6✔
545

546
#
547
# constants (from SWI-Prolog.h)
548
# /* PL_unify_term( arguments */
549

550

551
if PL_VERSION < 80200:
6✔
552
    # constants (from SWI-Prolog.h)
553
    # PL_unify_term() arguments
554
    PL_VARIABLE = 1  # nothing
×
555
    PL_ATOM = 2  # const char
×
556
    PL_INTEGER = 3  # int
×
557
    PL_FLOAT = 4  # double
×
558
    PL_STRING = 5  # const char *
×
559
    PL_TERM = 6  #
×
560
    # PL_unify_term()
561
    PL_FUNCTOR = 10  # functor_t, arg ...
×
562
    PL_LIST = 11  # length, arg ...
×
563
    PL_CHARS = 12  # const char *
×
564
    PL_POINTER = 13  # void *
×
565
    #               /* PlArg::PlArg(text, type) */
566
    # define PL_CODE_LIST     (14)       /* [ascii...] */
567
    # define PL_CHAR_LIST     (15)       /* [h,e,l,l,o] */
568
    # define PL_BOOL      (16)       /* PL_set_feature() */
569
    # define PL_FUNCTOR_CHARS (17)       /* PL_unify_term() */
570
    # define _PL_PREDICATE_INDICATOR (18)    /* predicate_t (Procedure) */
571
    # define PL_SHORT     (19)       /* short */
572
    # define PL_INT       (20)       /* int */
573
    # define PL_LONG      (21)       /* long */
574
    # define PL_DOUBLE    (22)       /* double */
575
    # define PL_NCHARS    (23)       /* unsigned, const char * */
576
    # define PL_UTF8_CHARS    (24)       /* const char * */
577
    # define PL_UTF8_STRING   (25)       /* const char * */
578
    # define PL_INT64     (26)       /* int64_t */
579
    # define PL_NUTF8_CHARS   (27)       /* unsigned, const char * */
580
    # define PL_NUTF8_CODES   (29)       /* unsigned, const char * */
581
    # define PL_NUTF8_STRING  (30)       /* unsigned, const char * */
582
    # define PL_NWCHARS   (31)       /* unsigned, const wchar_t * */
583
    # define PL_NWCODES   (32)       /* unsigned, const wchar_t * */
584
    # define PL_NWSTRING  (33)       /* unsigned, const wchar_t * */
585
    # define PL_MBCHARS   (34)       /* const char * */
586
    # define PL_MBCODES   (35)       /* const char * */
587
    # define PL_MBSTRING  (36)       /* const char * */
588

589
    REP_ISO_LATIN_1 = 0x0000  # output representation
×
590
    REP_UTF8 = 0x1000
×
591
    REP_MB = 0x2000
×
592

593
else:
594
    PL_VARIABLE = 1  # nothing
6✔
595
    PL_ATOM = 2  # const char *
6✔
596
    PL_INTEGER = 3  # int
6✔
597
    PL_RATIONAL = 4  # rational number
6✔
598
    PL_FLOAT = 5  # double
6✔
599
    PL_STRING = 6  # const char *
6✔
600
    PL_TERM = 7
6✔
601

602
    PL_NIL = 8  # The constant []
6✔
603
    PL_BLOB = 9  # non-atom blob
6✔
604
    PL_LIST_PAIR = 10  # [_|_] term
6✔
605

606
    # # PL_unify_term(
607
    PL_FUNCTOR = 11  # functor_t, arg ...
6✔
608
    PL_LIST = 12  # length, arg ...
6✔
609
    PL_CHARS = 13  # const char *
6✔
610
    PL_POINTER = 14  # void *
6✔
611
    # PlArg::PlArg(text, type
612
    PL_CODE_LIST = 15  # [ascii...]
6✔
613
    PL_CHAR_LIST = 16  # [h,e,l,l,o]
6✔
614
    PL_BOOL = 17  # PL_set_prolog_flag(
6✔
615
    PL_FUNCTOR_CHARS = 18  # PL_unify_term(
6✔
616
    _PL_PREDICATE_INDICATOR = 19  # predicate_t= Procedure
6✔
617
    PL_SHORT = 20  # short
6✔
618
    PL_INT = 21  # int
6✔
619
    PL_LONG = 22  # long
6✔
620
    PL_DOUBLE = 23  # double
6✔
621
    PL_NCHARS = 24  # size_t, const char *
6✔
622
    PL_UTF8_CHARS = 25  # const char *
6✔
623
    PL_UTF8_STRING = 26  # const char *
6✔
624
    PL_INT64 = 27  # int64_t
6✔
625
    PL_NUTF8_CHARS = 28  # size_t, const char *
6✔
626
    PL_NUTF8_CODES = 29  # size_t, const char *
6✔
627
    PL_NUTF8_STRING = 30  # size_t, const char *
6✔
628
    PL_NWCHARS = 31  # size_t, const wchar_t *
6✔
629
    PL_NWCODES = 32  # size_t, const wchar_t *
6✔
630
    PL_NWSTRING = 33  # size_t, const wchar_t *
6✔
631
    PL_MBCHARS = 34  # const char *
6✔
632
    PL_MBCODES = 35  # const char *
6✔
633
    PL_MBSTRING = 36  # const char *
6✔
634
    PL_INTPTR = 37  # intptr_t
6✔
635
    PL_CHAR = 38  # int
6✔
636
    PL_CODE = 39  # int
6✔
637
    PL_BYTE = 40  # int
6✔
638
    # PL_skip_list(
639
    PL_PARTIAL_LIST = 41  # a partial list
6✔
640
    PL_CYCLIC_TERM = 42  # a cyclic list/term
6✔
641
    PL_NOT_A_LIST = 43  # Object is not a list
6✔
642
    # dicts
643
    PL_DICT = 44
6✔
644

645
    REP_ISO_LATIN_1 = 0x0000  # output representation
6✔
646
    REP_UTF8 = 0x00100000
6✔
647
    REP_MB = 0x00200000
6✔
648

649
#       /********************************
650
#       * NON-DETERMINISTIC CALL/RETURN *
651
#       *********************************/
652
#
653
#  Note 1: Non-deterministic foreign functions may also use the deterministic
654
#    return methods PL_succeed and PL_fail.
655
#
656
#  Note 2: The argument to PL_retry is a 30 bits signed integer (long).
657

658
PL_FIRST_CALL = 0
6✔
659
PL_CUTTED = 1
6✔
660
PL_PRUNED = PL_CUTTED
6✔
661
PL_REDO = 2
6✔
662

663
PL_FA_NOTRACE = 0x01  # foreign cannot be traced
6✔
664
PL_FA_TRANSPARENT = 0x02  # foreign is module transparent
6✔
665
PL_FA_NONDETERMINISTIC = 0x04  # foreign is non-deterministic
6✔
666
PL_FA_VARARGS = 0x08  # call using t0, ac, ctx
6✔
667
PL_FA_CREF = 0x10  # Internal: has clause-reference */
6✔
668

669
#        /*******************************
670
#        *       CALL-BACK      *
671
#        *******************************/
672

673
PL_Q_DEBUG = 0x01  # = TRUE for backward compatibility
6✔
674
PL_Q_NORMAL = 0x02  # normal usage
6✔
675
PL_Q_NODEBUG = 0x04  # use this one
6✔
676
PL_Q_CATCH_EXCEPTION = 0x08  # handle exceptions in C
6✔
677
PL_Q_PASS_EXCEPTION = 0x10  # pass to parent environment
6✔
678
PL_Q_DETERMINISTIC = 0x20  # call was deterministic
6✔
679

680
#        /*******************************
681
#        *         BLOBS        *
682
#        *******************************/
683

684
# define PL_BLOB_MAGIC_B 0x75293a00  /* Magic to validate a blob-type */
685
# define PL_BLOB_VERSION 1       /* Current version */
686
# define PL_BLOB_MAGIC   (PL_BLOB_MAGIC_B|PL_BLOB_VERSION)
687

688
# define PL_BLOB_UNIQUE  0x01        /* Blob content is unique */
689
# define PL_BLOB_TEXT    0x02        /* blob contains text */
690
# define PL_BLOB_NOCOPY  0x04        /* do not copy the data */
691
# define PL_BLOB_WCHAR   0x08        /* wide character string */
692

693
#        /*******************************
694
#        *      CHAR BUFFERS    *
695
#        *******************************/
696

697
# Changed in 8.1.22
698
if PL_VERSION < 80122:
6✔
699
    CVT_ATOM = 0x0001
×
700
    CVT_STRING = 0x0002
×
701
    CVT_LIST = 0x0004
×
702
    CVT_INTEGER = 0x0008
×
703
    CVT_FLOAT = 0x0010
×
704
    CVT_VARIABLE = 0x0020
×
705
    CVT_NUMBER = CVT_INTEGER | CVT_FLOAT
×
706
    CVT_ATOMIC = CVT_NUMBER | CVT_ATOM | CVT_STRING
×
707
    CVT_WRITE = 0x0040  # as of version 3.2.10
×
708
    CVT_ALL = CVT_ATOMIC | CVT_LIST
×
709
    CVT_MASK = 0x00FF
×
710

711
    BUF_DISCARDABLE = 0x0000
×
712
    BUF_RING = 0x0100
×
713
    BUF_MALLOC = 0x0200
×
714

715
    CVT_EXCEPTION = 0x10000  # throw exception on error
×
716
else:
717
    CVT_ATOM = 0x00000001
6✔
718
    CVT_STRING = 0x00000002
6✔
719
    CVT_LIST = 0x00000004
6✔
720
    CVT_INTEGER = 0x00000008
6✔
721
    CVT_RATIONAL = 0x00000010
6✔
722
    CVT_FLOAT = 0x00000020
6✔
723
    CVT_VARIABLE = 0x00000040
6✔
724
    CVT_NUMBER = CVT_RATIONAL | CVT_FLOAT
6✔
725
    CVT_ATOMIC = CVT_NUMBER | CVT_ATOM | CVT_STRING
6✔
726
    CVT_WRITE = 0x00000080
6✔
727
    CVT_WRITE_CANONICAL = 0x00000080
6✔
728
    CVT_WRITEQ = 0x000000C0
6✔
729
    CVT_ALL = CVT_ATOMIC | CVT_LIST
6✔
730
    CVT_MASK = 0x00000FFF
6✔
731

732
    BUF_DISCARDABLE = 0x00000000
6✔
733
    BUF_STACK = 0x00010000
6✔
734
    BUF_RING = BUF_STACK
6✔
735
    BUF_MALLOC = 0x00020000
6✔
736
    BUF_ALLOW_STACK = 0x00040000
6✔
737

738
    CVT_EXCEPTION = 0x00001000  # throw exception on error
6✔
739

740
argv = list_to_bytes_list(sys.argv + [None])
6✔
741
argc = len(sys.argv)
6✔
742

743
#                  /*******************************
744
#                  *             TYPES            *
745
#                  *******************************/
746
#
747
# typedef uintptr_t       atom_t;         /* Prolog atom */
748
# typedef uintptr_t       functor_t;      /* Name/arity pair */
749
# typedef void *          module_t;       /* Prolog module */
750
# typedef void *          predicate_t;    /* Prolog procedure */
751
# typedef void *          record_t;       /* Prolog recorded term */
752
# typedef uintptr_t       term_t;         /* opaque term handle */
753
# typedef uintptr_t       qid_t;          /* opaque query handle */
754
# typedef uintptr_t       PL_fid_t;       /* opaque foreign context handle */
755
# typedef void *          control_t;      /* non-deterministic control arg */
756
# typedef void *          PL_engine_t;    /* opaque engine handle */
757
# typedef uintptr_t       PL_atomic_t;    /* same a word */
758
# typedef uintptr_t       foreign_t;      /* return type of foreign functions */
759
# typedef wchar_t         pl_wchar_t;     /* Prolog wide character */
760
# typedef foreign_t       (*pl_function_t)(); /* foreign language functions */
761
# typedef uintptr_t       buf_mark_t;     /* buffer mark handle */
762

763
atom_t = c_uint_p
6✔
764
functor_t = c_uint_p
6✔
765
module_t = c_void_p
6✔
766
predicate_t = c_void_p
6✔
767
record_t = c_void_p
6✔
768
term_t = c_uint_p
6✔
769
qid_t = c_uint_p
6✔
770
PL_fid_t = c_uint_p
6✔
771
fid_t = c_uint_p
6✔
772
control_t = c_void_p
6✔
773
PL_engine_t = c_void_p
6✔
774
PL_atomic_t = c_uint_p
6✔
775
foreign_t = c_uint_p
6✔
776
pl_wchar_t = c_wchar
6✔
777
intptr_t = c_long
6✔
778
ssize_t = intptr_t
6✔
779
wint_t = c_uint
6✔
780
buf_mark_t = c_uint_p
6✔
781

782
PL_initialise = _lib.PL_initialise
6✔
783
PL_initialise = check_strings(None, 1)(PL_initialise)
6✔
784

785
PL_mark_string_buffers = _lib.PL_mark_string_buffers
6✔
786
PL_mark_string_buffers.argtypes = [buf_mark_t]
6✔
787

788
PL_release_string_buffers_from_mark = _lib.PL_release_string_buffers_from_mark
6✔
789
PL_release_string_buffers_from_mark.argtypes = [buf_mark_t]
6✔
790

791

792
@contextmanager
6✔
793
def PL_STRINGS_MARK():
6✔
794
    __PL_mark = buf_mark_t()
6✔
795
    PL_mark_string_buffers(byref(__PL_mark))
6✔
796
    try:
6✔
797
        yield
6✔
798
    finally:
799
        PL_release_string_buffers_from_mark(__PL_mark)
6✔
800

801

802
PL_open_foreign_frame = _lib.PL_open_foreign_frame
6✔
803
PL_open_foreign_frame.restype = fid_t
6✔
804

805
PL_foreign_control = _lib.PL_foreign_control
6✔
806
PL_foreign_control.argtypes = [control_t]
6✔
807
PL_foreign_control.restype = c_int
6✔
808

809
PL_foreign_context = _lib.PL_foreign_context
6✔
810
PL_foreign_context.argtypes = [control_t]
6✔
811
PL_foreign_context.restype = intptr_t
6✔
812

813
PL_retry = _lib._PL_retry
6✔
814
PL_retry.argtypes = [intptr_t]
6✔
815
PL_retry.restype = foreign_t
6✔
816

817
PL_new_term_ref = _lib.PL_new_term_ref
6✔
818
PL_new_term_ref.restype = term_t
6✔
819

820
PL_new_term_refs = _lib.PL_new_term_refs
6✔
821
PL_new_term_refs.argtypes = [c_int]
6✔
822
PL_new_term_refs.restype = term_t
6✔
823

824
PL_chars_to_term = _lib.PL_chars_to_term
6✔
825
PL_chars_to_term.argtypes = [c_char_p, term_t]
6✔
826
PL_chars_to_term.restype = c_int
6✔
827

828
PL_chars_to_term = check_strings(0, None)(PL_chars_to_term)
6✔
829

830
PL_call = _lib.PL_call
6✔
831
PL_call.argtypes = [term_t, module_t]
6✔
832
PL_call.restype = c_int
6✔
833

834
PL_call_predicate = _lib.PL_call_predicate
6✔
835
PL_call_predicate.argtypes = [module_t, c_int, predicate_t, term_t]
6✔
836
PL_call_predicate.restype = c_int
6✔
837

838
PL_discard_foreign_frame = _lib.PL_discard_foreign_frame
6✔
839
PL_discard_foreign_frame.argtypes = [fid_t]
6✔
840
PL_discard_foreign_frame.restype = None
6✔
841

842
PL_put_chars = _lib.PL_put_chars
6✔
843
PL_put_chars.argtypes = [term_t, c_int, c_size_t, c_char_p]
6✔
844
PL_put_chars.restype = c_int
6✔
845

846
PL_put_list_chars = _lib.PL_put_list_chars
6✔
847
PL_put_list_chars.argtypes = [term_t, c_char_p]
6✔
848
PL_put_list_chars.restype = c_int
6✔
849

850
PL_put_list_chars = check_strings(1, None)(PL_put_list_chars)
6✔
851

852
# PL_EXPORT(void)                PL_register_atom(atom_t a);
853
PL_register_atom = _lib.PL_register_atom
6✔
854
PL_register_atom.argtypes = [atom_t]
6✔
855
PL_register_atom.restype = None
6✔
856

857
# PL_EXPORT(void)                PL_unregister_atom(atom_t a);
858
PL_unregister_atom = _lib.PL_unregister_atom
6✔
859
PL_unregister_atom.argtypes = [atom_t]
6✔
860
PL_unregister_atom.restype = None
6✔
861

862
# PL_EXPORT(atom_t)      PL_functor_name(functor_t f);
863
PL_functor_name = _lib.PL_functor_name
6✔
864
PL_functor_name.argtypes = [functor_t]
6✔
865
PL_functor_name.restype = atom_t
6✔
866

867
# PL_EXPORT(int)         PL_functor_arity(functor_t f);
868
PL_functor_arity = _lib.PL_functor_arity
6✔
869
PL_functor_arity.argtypes = [functor_t]
6✔
870
PL_functor_arity.restype = c_int
6✔
871

872
#                       /* Get C-values from Prolog terms */
873
# PL_EXPORT(int)         PL_get_atom(term_t t, atom_t *a);
874
PL_get_atom = _lib.PL_get_atom
6✔
875
PL_get_atom.argtypes = [term_t, POINTER(atom_t)]
6✔
876
PL_get_atom.restype = c_int
6✔
877

878
# PL_EXPORT(int)         PL_get_bool(term_t t, int *value);
879
PL_get_bool = _lib.PL_get_bool
6✔
880
PL_get_bool.argtypes = [term_t, POINTER(c_int)]
6✔
881
PL_get_bool.restype = c_int
6✔
882

883
# PL_EXPORT(int)         PL_get_atom_chars(term_t t, char **a);
884
PL_get_atom_chars = _lib.PL_get_atom_chars  # FIXME
6✔
885
PL_get_atom_chars.argtypes = [term_t, POINTER(c_char_p)]
6✔
886
PL_get_atom_chars.restype = c_int
6✔
887

888
PL_get_atom_chars = check_strings(None, 1)(PL_get_atom_chars)
6✔
889

890
PL_get_string_chars = _lib.PL_get_string
6✔
891
PL_get_string_chars.argtypes = [term_t, POINTER(c_char_p), c_int_p]
6✔
892

893
PL_get_chars = _lib.PL_get_chars  # FIXME:
6✔
894
PL_get_chars.argtypes = [term_t, POINTER(c_char_p), c_uint]
6✔
895
PL_get_chars.restype = c_int
6✔
896

897
PL_get_chars = check_strings(None, 1)(PL_get_chars)
6✔
898

899
PL_get_integer = _lib.PL_get_integer
6✔
900
PL_get_integer.argtypes = [term_t, POINTER(c_int)]
6✔
901
PL_get_integer.restype = c_int
6✔
902

903
PL_get_long = _lib.PL_get_long
6✔
904
PL_get_long.argtypes = [term_t, POINTER(c_long)]
6✔
905
PL_get_long.restype = c_int
6✔
906

907
PL_get_float = _lib.PL_get_float
6✔
908
PL_get_float.argtypes = [term_t, c_double_p]
6✔
909
PL_get_float.restype = c_int
6✔
910

911
PL_get_functor = _lib.PL_get_functor
6✔
912
PL_get_functor.argtypes = [term_t, POINTER(functor_t)]
6✔
913
PL_get_functor.restype = c_int
6✔
914

915
PL_get_name_arity = _lib.PL_get_name_arity
6✔
916
PL_get_name_arity.argtypes = [term_t, POINTER(atom_t), POINTER(c_int)]
6✔
917
PL_get_name_arity.restype = c_int
6✔
918

919
PL_get_arg = _lib.PL_get_arg
6✔
920
PL_get_arg.argtypes = [c_int, term_t, term_t]
6✔
921
PL_get_arg.restype = c_int
6✔
922

923
PL_get_head = _lib.PL_get_head
6✔
924
PL_get_head.argtypes = [term_t, term_t]
6✔
925
PL_get_head.restype = c_int
6✔
926

927
PL_get_tail = _lib.PL_get_tail
6✔
928
PL_get_tail.argtypes = [term_t, term_t]
6✔
929
PL_get_tail.restype = c_int
6✔
930

931
PL_get_nil = _lib.PL_get_nil
6✔
932
PL_get_nil.argtypes = [term_t]
6✔
933
PL_get_nil.restype = c_int
6✔
934

935
PL_put_atom_chars = _lib.PL_put_atom_chars
6✔
936
PL_put_atom_chars.argtypes = [term_t, c_char_p]
6✔
937
PL_put_atom_chars.restype = c_int
6✔
938

939
PL_put_atom_chars = check_strings(1, None)(PL_put_atom_chars)
6✔
940

941
PL_atom_chars = _lib.PL_atom_chars
6✔
942
PL_atom_chars.argtypes = [atom_t]
6✔
943
PL_atom_chars.restype = c_char_p
6✔
944

945
PL_atom_wchars = _lib.PL_atom_wchars
6✔
946
PL_atom_wchars.argtypes = [atom_t, POINTER(c_size_t)]
6✔
947
PL_atom_wchars.restype = c_wchar_p
6✔
948

949
PL_predicate = _lib.PL_predicate
6✔
950
PL_predicate.argtypes = [c_char_p, c_int, c_char_p]
6✔
951
PL_predicate.restype = predicate_t
6✔
952

953
PL_predicate = check_strings([0, 2], None)(PL_predicate)
6✔
954

955
PL_pred = _lib.PL_pred
6✔
956
PL_pred.argtypes = [functor_t, module_t]
6✔
957
PL_pred.restype = predicate_t
6✔
958

959
PL_open_query = _lib.PL_open_query
6✔
960
PL_open_query.argtypes = [module_t, c_int, predicate_t, term_t]
6✔
961
PL_open_query.restype = qid_t
6✔
962

963
PL_next_solution = _lib.PL_next_solution
6✔
964
PL_next_solution.argtypes = [qid_t]
6✔
965
PL_next_solution.restype = c_int
6✔
966

967
PL_copy_term_ref = _lib.PL_copy_term_ref
6✔
968
PL_copy_term_ref.argtypes = [term_t]
6✔
969
PL_copy_term_ref.restype = term_t
6✔
970

971
PL_get_list = _lib.PL_get_list
6✔
972
PL_get_list.argtypes = [term_t, term_t, term_t]
6✔
973
PL_get_list.restype = c_int
6✔
974

975
PL_get_chars = _lib.PL_get_chars  # FIXME
6✔
976

977
PL_close_query = _lib.PL_close_query
6✔
978
PL_close_query.argtypes = [qid_t]
6✔
979
PL_close_query.restype = None
6✔
980

981
PL_cut_query = _lib.PL_cut_query
6✔
982
PL_cut_query.argtypes = [qid_t]
6✔
983
PL_cut_query.restype = None
6✔
984

985
PL_halt = _lib.PL_halt
6✔
986
PL_halt.argtypes = [c_int]
6✔
987
PL_halt.restype = None
6✔
988

989
PL_cleanup = _lib.PL_cleanup
6✔
990
PL_cleanup.restype = c_int
6✔
991

992
PL_unify_integer = _lib.PL_unify_integer
6✔
993
PL_unify_atom_chars = _lib.PL_unify_atom_chars
6✔
994

995
PL_unify_float = _lib.PL_unify_float
6✔
996
PL_unify_float.argtypes = [term_t, c_double]
6✔
997
PL_unify_float.restype = c_int
6✔
998

999
PL_unify_bool = _lib.PL_unify_bool
6✔
1000
PL_unify_bool.argtypes = [term_t, c_int]
6✔
1001
PL_unify_bool.restype = c_int
6✔
1002

1003
PL_unify_list = _lib.PL_unify_list
6✔
1004
PL_unify_list.argtypes = [term_t, term_t, term_t]
6✔
1005
PL_unify_list.restype = c_int
6✔
1006

1007
PL_unify_nil = _lib.PL_unify_nil
6✔
1008
PL_unify_nil.argtypes = [term_t]
6✔
1009
PL_unify_nil.restype = c_int
6✔
1010

1011
PL_unify_atom = _lib.PL_unify_atom
6✔
1012
PL_unify_atom.argtypes = [term_t, atom_t]
6✔
1013
PL_unify_atom.restype = c_int
6✔
1014

1015
PL_unify_atom_chars = _lib.PL_unify_atom_chars
6✔
1016
PL_unify_atom_chars.argtypes = [term_t, c_char_p]
6✔
1017
PL_unify_atom_chars.restype = c_int
6✔
1018

1019
PL_unify_string_chars = _lib.PL_unify_string_chars
6✔
1020
PL_unify_string_chars.argtypes = [term_t, c_char_p]
6✔
1021
PL_unify_string_chars.restype = c_void_p
6✔
1022

1023
PL_foreign_control = _lib.PL_foreign_control
6✔
1024
PL_foreign_control.argtypes = [control_t]
6✔
1025
PL_foreign_control.restypes = c_int
6✔
1026

1027
PL_foreign_context_address = _lib.PL_foreign_context_address
6✔
1028
PL_foreign_context_address.argtypes = [control_t]
6✔
1029
PL_foreign_context_address.restypes = c_void_p
6✔
1030

1031
PL_retry_address = _lib._PL_retry_address
6✔
1032
PL_retry_address.argtypes = [c_void_p]
6✔
1033
PL_retry_address.restypes = foreign_t
6✔
1034

1035
PL_unify = _lib.PL_unify
6✔
1036
PL_unify.restype = c_int
6✔
1037

1038
PL_succeed = 1
6✔
1039

1040
PL_unify_arg = _lib.PL_unify_arg
6✔
1041
PL_unify_arg.argtypes = [c_int, term_t, term_t]
6✔
1042
PL_unify_arg.restype = c_int
6✔
1043

1044
# Verify types
1045

1046
PL_term_type = _lib.PL_term_type
6✔
1047
PL_term_type.argtypes = [term_t]
6✔
1048
PL_term_type.restype = c_int
6✔
1049

1050
PL_is_variable = _lib.PL_is_variable
6✔
1051
PL_is_variable.argtypes = [term_t]
6✔
1052
PL_is_variable.restype = c_int
6✔
1053

1054
PL_is_ground = _lib.PL_is_ground
6✔
1055
PL_is_ground.argtypes = [term_t]
6✔
1056
PL_is_ground.restype = c_int
6✔
1057

1058
PL_is_atom = _lib.PL_is_atom
6✔
1059
PL_is_atom.argtypes = [term_t]
6✔
1060
PL_is_atom.restype = c_int
6✔
1061

1062
PL_is_integer = _lib.PL_is_integer
6✔
1063
PL_is_integer.argtypes = [term_t]
6✔
1064
PL_is_integer.restype = c_int
6✔
1065

1066
PL_is_string = _lib.PL_is_string
6✔
1067
PL_is_string.argtypes = [term_t]
6✔
1068
PL_is_string.restype = c_int
6✔
1069

1070
PL_is_float = _lib.PL_is_float
6✔
1071
PL_is_float.argtypes = [term_t]
6✔
1072
PL_is_float.restype = c_int
6✔
1073

1074
PL_is_compound = _lib.PL_is_compound
6✔
1075
PL_is_compound.argtypes = [term_t]
6✔
1076
PL_is_compound.restype = c_int
6✔
1077

1078
PL_is_functor = _lib.PL_is_functor
6✔
1079
PL_is_functor.argtypes = [term_t, functor_t]
6✔
1080
PL_is_functor.restype = c_int
6✔
1081

1082
PL_is_list = _lib.PL_is_list
6✔
1083
PL_is_list.argtypes = [term_t]
6✔
1084
PL_is_list.restype = c_int
6✔
1085

1086
PL_is_atomic = _lib.PL_is_atomic
6✔
1087
PL_is_atomic.argtypes = [term_t]
6✔
1088
PL_is_atomic.restype = c_int
6✔
1089

1090
PL_is_number = _lib.PL_is_number
6✔
1091
PL_is_number.argtypes = [term_t]
6✔
1092
PL_is_number.restype = c_int
6✔
1093

1094
PL_put_variable = _lib.PL_put_variable
6✔
1095
PL_put_variable.argtypes = [term_t]
6✔
1096
PL_put_variable.restype = None
6✔
1097

1098
PL_put_integer = _lib.PL_put_integer
6✔
1099
PL_put_integer.argtypes = [term_t, c_long]
6✔
1100
PL_put_integer.restype = None
6✔
1101

1102
PL_put_functor = _lib.PL_put_functor
6✔
1103
PL_put_functor.argtypes = [term_t, functor_t]
6✔
1104
PL_put_functor.restype = None
6✔
1105

1106
PL_put_list = _lib.PL_put_list
6✔
1107
PL_put_list.argtypes = [term_t]
6✔
1108
PL_put_list.restype = None
6✔
1109

1110
PL_put_nil = _lib.PL_put_nil
6✔
1111
PL_put_nil.argtypes = [term_t]
6✔
1112
PL_put_nil.restype = None
6✔
1113

1114
PL_put_term = _lib.PL_put_term
6✔
1115
PL_put_term.argtypes = [term_t, term_t]
6✔
1116
PL_put_term.restype = None
6✔
1117

1118
PL_cons_functor = _lib.PL_cons_functor  # FIXME:
6✔
1119

1120
PL_cons_functor_v = _lib.PL_cons_functor_v
6✔
1121
PL_cons_functor_v.argtypes = [term_t, functor_t, term_t]
6✔
1122
PL_cons_functor_v.restype = None
6✔
1123

1124
PL_cons_list = _lib.PL_cons_list
6✔
1125
PL_cons_list.argtypes = [term_t, term_t, term_t]
6✔
1126
PL_cons_list.restype = None
6✔
1127

1128
PL_exception = _lib.PL_exception
6✔
1129
PL_exception.argtypes = [qid_t]
6✔
1130
PL_exception.restype = term_t
6✔
1131

1132
PL_register_foreign = _lib.PL_register_foreign
6✔
1133
PL_register_foreign = check_strings(0, None)(PL_register_foreign)
6✔
1134

1135
PL_new_atom = _lib.PL_new_atom
6✔
1136
PL_new_atom.argtypes = [c_char_p]
6✔
1137
PL_new_atom.restype = atom_t
6✔
1138

1139
PL_new_atom = check_strings(0, None)(PL_new_atom)
6✔
1140

1141
PL_new_functor = _lib.PL_new_functor
6✔
1142
PL_new_functor.argtypes = [atom_t, c_int]
6✔
1143
PL_new_functor.restype = functor_t
6✔
1144

1145
PL_compare = _lib.PL_compare
6✔
1146
PL_compare.argtypes = [term_t, term_t]
6✔
1147
PL_compare.restype = c_int
6✔
1148

1149
PL_same_compound = _lib.PL_same_compound
6✔
1150
PL_same_compound.argtypes = [term_t, term_t]
6✔
1151
PL_same_compound.restype = c_int
6✔
1152

1153
PL_record = _lib.PL_record
6✔
1154
PL_record.argtypes = [term_t]
6✔
1155
PL_record.restype = record_t
6✔
1156

1157
PL_recorded = _lib.PL_recorded
6✔
1158
PL_recorded.argtypes = [record_t, term_t]
6✔
1159
PL_recorded.restype = None
6✔
1160

1161
PL_erase = _lib.PL_erase
6✔
1162
PL_erase.argtypes = [record_t]
6✔
1163
PL_erase.restype = None
6✔
1164

1165
PL_new_module = _lib.PL_new_module
6✔
1166
PL_new_module.argtypes = [atom_t]
6✔
1167
PL_new_module.restype = module_t
6✔
1168

1169
PL_is_initialised = _lib.PL_is_initialised
6✔
1170

1171
intptr_t = c_long
6✔
1172
ssize_t = intptr_t
6✔
1173
wint_t = c_uint
6✔
1174

1175
PL_thread_self = _lib.PL_thread_self
6✔
1176
PL_thread_self.restype = c_int
6✔
1177

1178
PL_thread_attach_engine = _lib.PL_thread_attach_engine
6✔
1179
PL_thread_attach_engine.argtypes = [c_void_p]
6✔
1180
PL_thread_attach_engine.restype = c_int
6✔
1181

1182

1183
class _mbstate_t_value(Union):
6✔
1184
    _fields_ = [("__wch", wint_t), ("__wchb", c_char * 4)]
6✔
1185

1186

1187
class mbstate_t(Structure):
6✔
1188
    _fields_ = [("__count", c_int), ("__value", _mbstate_t_value)]
6✔
1189

1190

1191
# stream related funcs
1192
Sread_function = CFUNCTYPE(ssize_t, c_void_p, c_char_p, c_size_t)
6✔
1193
Swrite_function = CFUNCTYPE(ssize_t, c_void_p, c_char_p, c_size_t)
6✔
1194
Sseek_function = CFUNCTYPE(c_long, c_void_p, c_long, c_int)
6✔
1195
Sseek64_function = CFUNCTYPE(c_int64, c_void_p, c_int64, c_int)
6✔
1196
Sclose_function = CFUNCTYPE(c_int, c_void_p)
6✔
1197
Scontrol_function = CFUNCTYPE(c_int, c_void_p, c_int, c_void_p)
6✔
1198

1199
# IOLOCK
1200
IOLOCK = c_void_p
6✔
1201

1202

1203
# IOFUNCTIONS
1204
class IOFUNCTIONS(Structure):
6✔
1205
    _fields_ = [
6✔
1206
        ("read", Sread_function),
1207
        ("write", Swrite_function),
1208
        ("seek", Sseek_function),
1209
        ("close", Sclose_function),
1210
        ("seek64", Sseek64_function),
1211
        ("reserved", intptr_t * 2),
1212
    ]
1213

1214

1215
# IOENC
1216
(
6✔
1217
    ENC_UNKNOWN,
1218
    ENC_OCTET,
1219
    ENC_ASCII,
1220
    ENC_ISO_LATIN_1,
1221
    ENC_ANSI,
1222
    ENC_UTF8,
1223
    ENC_UNICODE_BE,
1224
    ENC_UNICODE_LE,
1225
    ENC_WCHAR,
1226
) = tuple(range(9))
1227
IOENC = c_int
6✔
1228

1229

1230
# IOPOS
1231
class IOPOS(Structure):
6✔
1232
    _fields_ = [
6✔
1233
        ("byteno", c_int64),
1234
        ("charno", c_int64),
1235
        ("lineno", c_int),
1236
        ("linepos", c_int),
1237
        ("reserved", intptr_t * 2),
1238
    ]
1239

1240

1241
# IOSTREAM
1242
class IOSTREAM(Structure):
6✔
1243
    _fields_ = [
6✔
1244
        ("bufp", c_char_p),
1245
        ("limitp", c_char_p),
1246
        ("buffer", c_char_p),
1247
        ("unbuffer", c_char_p),
1248
        ("lastc", c_int),
1249
        ("magic", c_int),
1250
        ("bufsize", c_int),
1251
        ("flags", c_int),
1252
        ("posbuf", IOPOS),
1253
        ("position", POINTER(IOPOS)),
1254
        ("handle", c_void_p),
1255
        ("functions", IOFUNCTIONS),
1256
        ("locks", c_int),
1257
        ("mutex", IOLOCK),
1258
        ("closure_hook", CFUNCTYPE(None, c_void_p)),
1259
        ("closure", c_void_p),
1260
        ("timeout", c_int),
1261
        ("message", c_char_p),
1262
        ("encoding", IOENC),
1263
    ]
1264

1265

1266
IOSTREAM._fields_.extend(
6✔
1267
    [("tee", IOSTREAM), ("mbstate", POINTER(mbstate_t)), ("reserved", intptr_t * 6)]
1268
)
1269

1270
Sopen_string = _lib.Sopen_string
6✔
1271
Sopen_string.argtypes = [POINTER(IOSTREAM), c_char_p, c_size_t, c_char_p]
6✔
1272
Sopen_string.restype = POINTER(IOSTREAM)
6✔
1273

1274
Sclose = _lib.Sclose
6✔
1275
Sclose.argtypes = [POINTER(IOSTREAM)]
6✔
1276

1277
PL_unify_stream = _lib.PL_unify_stream
6✔
1278
PL_unify_stream.argtypes = [term_t, POINTER(IOSTREAM)]
6✔
1279

1280

1281
# create an exit hook which captures the exit code for our cleanup function
1282
class ExitHook(object):
6✔
1283
    def __init__(self):
6✔
1284
        self.exit_code = None
6✔
1285
        self.exception = None
6✔
1286

1287
    def hook(self):
6✔
1288
        self._orig_exit = sys.exit
6✔
1289
        sys.exit = self.exit
6✔
1290

1291
    def exit(self, code=0):
6✔
1292
        self.exit_code = code
6✔
1293
        self._orig_exit(code)
6✔
1294

1295

1296
_hook = ExitHook()
6✔
1297
_hook.hook()
6✔
1298

1299
_isCleaned = False
6✔
1300
# create a property for Atom's delete method in order to avoid segmentation fault
1301
cleaned = property(_isCleaned)
6✔
1302

1303

1304
# register the cleanup function to be executed on system exit
1305
@atexit.register
6✔
1306
def cleanupProlog():
6✔
1307
    # only do something if prolog has been initialised
1308
    if PL_is_initialised(None, None):
6✔
1309
        # clean up the prolog system using the caught exit code
1310
        # if exit code is None, the program exits normally and we can use 0
1311
        # instead.
1312
        # TODO Prolog documentation says cleanup with code 0 may be interrupted
1313
        # If the program has come to an end the prolog system should not
1314
        # interfere with that. Therefore we may want to use 1 instead of 0.
1315
        PL_cleanup(int(_hook.exit_code or 0))
6✔
1316
        _isCleaned = True
6✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc