###
# Modern Albufeira Prolog Interpreter
#
# Warranty & Liability
# To the extent permitted by applicable law and unless explicitly
# otherwise agreed upon, XLOG Technologies AG makes no warranties
# regarding the provided information. XLOG Technologies AG assumes
# no liability that any problems might be solved with the information
# provided by XLOG Technologies AG.
#
# Rights & License
# All industrial property rights regarding the information - copyright
# and patent rights in particular - are the sole property of XLOG
# Technologies AG. If the company was not the originator of some
# excerpts, XLOG Technologies AG has at least obtained the right to
# reproduce, change and translate the information.
#
# Reproduction is restricted to the whole unaltered document. Reproduction
# of the information is only allowed for non-commercial uses. Selling,
# giving away or letting of the execution of the library is prohibited.
# The library can be distributed as part of your applications and libraries
# for execution provided this comment remains unchanged.
#
# Restrictions
# Only to be distributed with programs that add significant and primary
# functionality to the library. Not to be distributed with additional
# software intended to replace any components of the library.
#
# Trademarks
# Jekejeke is a registered trademark of XLOG Technologies AG.
##
from nova.core import (
is_number, VOID_ARGS, Compound, is_structure, check_integer,
set, get_cont, check_atomic, exec_build, exec_unify,
VAR_MASK_SEEN, deref, make_special, cont, make_error,
Variable, Item, stack_push, stack_peek, is_integer,
stack_pop, walk_vars, make_check, bind, is_compound)
####################################################################
# numbervars/3 #
####################################################################
###
# numbervars(X, N, M):
# The predicate succeeds in M with the next index after
# numbering all variables in X starting with index N.
##
def test_numbervars(args):
alpha = exec_build(args[0])
beta = exec_build(args[1])
check_integer(beta)
if beta >= 0:
beta = numbervars("$VAR", alpha, beta)
else:
beta = (-1) - beta
beta = numbervars("_", alpha, beta)
beta = (-1) - beta
return exec_unify(args[2], beta)
def numbervars(functor, alpha, beta):
def numbervars2(node):
nonlocal beta
bind(Compound(functor, [beta]), node)
beta += 1
return False
walk_vars(alpha, lambda node: False, VAR_MASK_SEEN)
walk_vars(alpha, numbervars2, 0)
return beta
################################################################
# Association Map #
################################################################
def assoc_get(vmap, key):
if vmap is None:
return NotImplemented
return vmap.get(key, NotImplemented)
def assoc_set(vmap, key, value):
if vmap is None:
vmap = {}
vmap[key] = value
return vmap
################################################################
# Unary Work #
################################################################
###
# Create an unary work item.
#
# @param first The Prolog term.
# @param idx The index.
##
class Shuttle:
def __init__(self, first, idx):
self.first = first
self.idx = idx
################################################################
# unnumbervars/3 #
################################################################
###
# unnumbervars(S, N, T):
# The predicate succeeds in T with a copy of S with the
# numbering greater or equal than N replaced by variables.
##
def test_unnumbervars(args):
alpha = exec_build(args[0])
beta = exec_build(args[1])
check_integer(beta)
try:
if beta >= 0:
res = walk_replace("$VAR", beta, alpha)
else:
res = (-1) - beta
res = walk_replace("_", res, alpha)
finally:
if beta >= 0:
walk_unmax("$VAR", alpha)
else:
walk_unmax("_", alpha)
return exec_unify(args[2], res)
def walk_replace(functor, beta, first):
stack = None
vmap = None
while True:
first = deref(first)
if is_structure(first):
if (functor == first.functor and
len(first.args) == 1):
peek = deref(first.args[0])
if is_integer(peek) and beta <= peek:
first = assoc_get(vmap, peek)
if first is NotImplemented:
first = Variable()
vmap = assoc_set(vmap, peek, first)
if is_structure(first):
if not is_compound(first.functor):
first.functor = Compound(first.functor,
[NotImplemented] * len(first.args))
item = Item(first, None, 0)
stack = stack_push(stack, item)
first = first.args[0]
continue
else:
first = first.functor
item = stack_peek(stack)
while (item is not None and
item.idx == len(item.first.args) - 1):
item.first.functor.args[item.idx] = first
first = item.first.functor
stack_pop(stack)
item = stack_peek(stack)
if item is None:
return first
else:
item.first.functor.args[item.idx] = first
item.idx += 1
first = item.first.args[item.idx]
####################################################################
# maxvars/2 #
####################################################################
###
# maxvars(X, M):
# The predicate succeeds in M with the max numbering of the term X.
##
def test_maxvars(args):
alpha = exec_build(args[0])
try:
res = walk_max("$VAR", alpha)
finally:
walk_unmax("$VAR", alpha)
return exec_unify(args[1], res)
def walk_max(functor, first):
stack = None
res = -1
while True:
first = deref(first)
if is_structure(first):
if (functor == first.functor and
len(first.args) == 1):
peek = deref(first.args[0])
if is_integer(peek):
if res < peek:
res = peek
first = None
if first is not None:
if not is_compound(first.functor):
first.functor = Compound(
first.functor, VOID_ARGS)
if 0 != len(first.args) - 1:
item = Item(first, None, 0)
stack = stack_push(stack, item)
first = first.args[0]
continue
item = stack_peek(stack)
if item is None:
return res
else:
item.idx += 1
first = item.first.args[item.idx]
if item.idx == len(item.first.args) - 1:
stack_pop(stack)
def walk_unmax(functor, first):
stack = None
while True:
first = deref(first)
if is_structure(first):
if (functor == first.functor and
len(first.args) == 1):
peek = deref(first.args[0])
if is_integer(peek):
first = None
if first is not None:
if is_compound(first.functor):
first.functor = first.functor.functor
if 0 != len(first.args) - 1:
item = Item(first, None, 0)
stack = stack_push(stack, item)
first = first.args[0]
continue
item = stack_peek(stack)
if item is None:
return
else:
item.idx += 1
first = item.first.args[item.idx]
if item.idx == len(item.first.args) - 1:
stack_pop(stack)
####################################################################
# call/2-4 #
####################################################################
###
# call(F, A1, .., An): [Corr.2 8.15.4.4]
# The predicate succeeds in calling the goal which results from
# appending the arguments A1, .., An to the callable F.
##
def special_calln(args):
alpha = deref(args[0])
if is_structure(alpha):
functor = alpha.functor
oldargs = alpha.args
else:
functor = alpha
check_atomic(functor)
oldargs = VOID_ARGS
arity = len(oldargs) + len(args) - 1
if arity == 0:
goal = functor
else:
if is_number(functor):
raise make_error(Compound("type_error", ["atom", functor]))
newargs = [NotImplemented] * arity
i = 0
while i < len(oldargs):
newargs[i] = deref(oldargs[i])
i += 1
i = 0
while i < len(args) - 1:
newargs[i + len(oldargs)] = deref(args[i + 1])
i += 1
goal = Compound(functor, newargs)
goal = Compound(".", [goal, get_cont().args[1]])
cont(goal)
return True
####################################################################
# Asm Lib Init #
####################################################################
def main():
set("numbervars", 3, make_check(test_numbervars))
set("unnumbervars", 3, make_check(test_unnumbervars))
set("maxvars", 2, make_check(test_maxvars))
set("call", 2, make_special(special_calln))
set("call", 3, make_special(special_calln))
set("call", 4, make_special(special_calln))
set("call", 5, make_special(special_calln))
set("call", 6, make_special(special_calln))
set("call", 7, make_special(special_calln))
set("call", 8, make_special(special_calln))