[pypy-svn] r43600 - in pypy/dist/pypy/lang/prolog/interpreter: . test

cfbolz at codespeak.net cfbolz at codespeak.net
Thu May 24 16:30:14 CEST 2007


Author: cfbolz
Date: Thu May 24 16:30:14 2007
New Revision: 43600

Modified:
   pypy/dist/pypy/lang/prolog/interpreter/arithmetic.py
   pypy/dist/pypy/lang/prolog/interpreter/error.py
   pypy/dist/pypy/lang/prolog/interpreter/helper.py
   pypy/dist/pypy/lang/prolog/interpreter/parsing.py
   pypy/dist/pypy/lang/prolog/interpreter/term.py
   pypy/dist/pypy/lang/prolog/interpreter/test/test_parsing.py
Log:
refactor arithmetic functions a bit. rename the .num attribute of Float
instances too floatval, to be less confusing.


Modified: pypy/dist/pypy/lang/prolog/interpreter/arithmetic.py
==============================================================================
--- pypy/dist/pypy/lang/prolog/interpreter/arithmetic.py	(original)
+++ pypy/dist/pypy/lang/prolog/interpreter/arithmetic.py	Thu May 24 16:30:14 2007
@@ -9,25 +9,83 @@
 
 pattern_to_function = {}
 
-def wrap_builtin_operation(pattern, unwrap_spec, can_overflow):
-    code = ["def f(engine, query):"]
+class CodeCollector(object):
+    def __init__(self):
+        self.code = []
+        self.blocks = []
+
+    def emit(self, line):
+        for line in line.split("\n"):
+            self.code.append(" " * (4 * len(self.blocks)) + line)
+
+    def start_block(self, blockstarter):
+        assert blockstarter.endswith(":")
+        self.emit(blockstarter)
+        self.blocks.append(blockstarter)
+
+    def end_block(self, starterpart=""):
+        block = self.blocks.pop()
+        assert starterpart in block, "ended wrong block %s with %s" % (
+            block, starterpart)
+
+    def tostring(self):
+        assert not self.blocks
+        return "\n".join(self.code)
+
+def wrap_builtin_operation(name, pattern, unwrap_spec, can_overflow, intversion):
+    code = CodeCollector()
+    code.start_block("def prolog_%s(engine, query):" % name)
     for i, spec in enumerate(unwrap_spec):
         varname = "var%s" % (i, )
-        code.append(
-            "    %s = eval_arithmetic(engine, query.args[%s])" % (varname, i))
-        code.append(
-            "    v%s = 0" % (i, ))
-        code.append("    if isinstance(%s, term.Number):" % (varname, ))
-        code.append("        v%s = %s.num" % (i, varname))
+        code.emit("%s = eval_arithmetic(engine, query.args[%s])" %
+                  (varname, i))
+    for i, spec in enumerate(unwrap_spec):
+        varname = "var%s" % (i, )
+        if spec == "int":
+            code.start_block(
+                "if not isinstance(%s, term.Number):" % (varname, ))
+            code.emit("error.throw_type_error('int', %s)" % (varname, ))
+            code.end_block("if")
+    if "expr" in unwrap_spec and intversion:
+        # check whether all arguments are ints
+        for i, spec in enumerate(unwrap_spec):
+            varname = "var%s" % (i, )
+            if spec == "int":
+                continue
+            code.start_block(
+                "if isinstance(%s, term.Number):" % (varname, ))
+            code.emit("v%s = var%s.num" % (i, i))
+        code.emit("return term.Number(int(%s))" % (pattern, ))
+        for i, spec in enumerate(unwrap_spec):
+            if spec == "int":
+                continue
+            code.end_block("if")
+    
+    #general case in an extra function
+    args = ", ".join(["var%s" % i for i in range(len(unwrap_spec))])
+    code.emit("return general_%s(%s)" % (name, args))
+    code.end_block("def")
+    code.start_block("def general_%s(%s):" % (name, args))
+    for i, spec in enumerate(unwrap_spec):
+        varname = "var%s" % (i, )
+        code.emit("v%s = 0" % (i, ))
+        code.start_block("if isinstance(%s, term.Number):" % (varname, ))
+        code.emit("v%s = %s.num" % (i, varname))
+        code.end_block("if")
+        expected = 'int'
         if spec == "expr":
-            code.append("    elif isinstance(%s, term.Float):" % (varname, ))
-            code.append("        v%s = %s.num" % (i, varname))
-        code.append("    else:")
-        code.append("        error.throw_type_error('int', %s)" % (varname, ))
-    code.append("    return norm_float(%s)" % pattern)
+            code.start_block("elif isinstance(%s, term.Float):" % (varname, ))
+            code.emit("v%s = %s.floatval" % (i, varname))
+            code.end_block("elif")
+            expected = 'float'
+        code.start_block("else:")
+        code.emit("error.throw_type_error('%s', %s)" % (expected, varname, ))
+        code.end_block("else")
+    code.emit("return norm_float(term.Float(%s))" % pattern)
+    code.end_block("def")
     miniglobals = globals().copy()
-    exec py.code.Source("\n".join(code)).compile() in miniglobals
-    return miniglobals['f']
+    exec py.code.Source(code.tostring()).compile() in miniglobals
+    return miniglobals["prolog_" + name]
 
 wrap_builtin_operation._annspecialcase_ = 'specialize:memo'
 
@@ -36,14 +94,14 @@
     if isinstance(query, term.Number):
         return query
     if isinstance(query, term.Float):
-        return norm_float(query.num)
+        return norm_float(query)
     if isinstance(query, term.Atom):
         #XXX beautify that
         if query.name == "pi":
             return term.Float(math.pi)
         if query.name == "e":
             return term.Float(math.e)
-        raise error.UncatchableError("not implemented")
+        error.throw_type_error("evaluable", query.get_prolog_signature())
     if isinstance(query, term.Term):
         func = arithmetic_functions.get(query.signature, None)
         if func is None:
@@ -51,37 +109,45 @@
         return func(engine, query)
     raise error.UncatchableError("not implemented")
 
-def norm_float(v):
+def norm_float(obj):
+    v = obj.floatval
     if v == int(v):
         return term.Number(int(v))
     else:
-        return term.Float(v)
+        return obj
 
 simple_functions = [
-    ("+",                     ["expr", "expr"], "v0 + v1", True),
-    ("-",                     ["expr", "expr"], "v0 - v1", True),
-    ("*",                     ["expr", "expr"], "v0 * v1", True),
-    ("//",                    ["int",  "int"],  "v0 / v1", True),
-    ("**",                    ["expr", "expr"], "v0 ** v1", True),
-    (">>",                    ["int", "int"],   "v0 >> v1", False),
-    ("<<",                    ["int", "int"],   "intmask(v0 << v1)", False),
-    ("\\/",                   ["int", "int"],   "v0 | v1", False),
-    ("/\\",                   ["int", "int"],   "v0 & v1", False),
-    ("xor",                   ["int", "int"],   "v0 ^ v1", False),
-    ("mod",                   ["int", "int"],   "v0 % v1", False),
-    ("\\",                    ["int"],          "v0 ^ 0", False),
-    ("abs",                   ["expr"],         "abs(v0)", True),
-#    ("max",                   ["expr", "expr"], "max(v0, v1)", False),
-#    ("min",                   ["expr", "expr"], "min(v0, v1)", False),
-    ("round",                 ["expr"],         "int(v0 + 0.5)", False),
-    ("floor",                 ["expr"],         "math.floor(v0)", False),
-    ("ceiling",               ["expr"],         "math.ceil(v0)", False),
-    ("floor",                 ["expr"],         "math.floor(v0)", False),
-    ("float_fractional_part", ["expr"],         "v0 - int(v0)", False),
-    ("float_integer_part",    ["expr"],         "int(v0)", False),
+    ("+",                     ["expr", "expr"], "v0 + v1", True, True),
+    ("-",                     ["expr", "expr"], "v0 - v1", True, True),
+    ("*",                     ["expr", "expr"], "v0 * v1", True, True),
+    ("//",                    ["int",  "int"],  "v0 / v1", True, False),
+    ("**",                    ["expr", "expr"], "v0 ** v1", True, True),
+    (">>",                    ["int", "int"],   "v0 >> v1", False, False),
+    ("<<",                    ["int", "int"],   "intmask(v0 << v1)", False,
+                                                                     False),
+    ("\\/",                   ["int", "int"],   "v0 | v1", False, False),
+    ("/\\",                   ["int", "int"],   "v0 & v1", False, False),
+    ("xor",                   ["int", "int"],   "v0 ^ v1", False, False),
+    ("mod",                   ["int", "int"],   "v0 % v1", False, False),
+    ("\\",                    ["int"],          "~v0", False, False),
+    ("abs",                   ["expr"],         "abs(v0)", True, True),
+    ("max",                   ["expr", "expr"], "max(v0, v1)", False, True),
+    ("min",                   ["expr", "expr"], "min(v0, v1)", False, True),
+    ("round",                 ["expr"],         "int(v0 + 0.5)", False, False),
+    ("floor",                 ["expr"],         "math.floor(v0)", False, True), #XXX
+    ("ceiling",               ["expr"],         "math.ceil(v0)", False, True), #XXX
+    ("float_fractional_part", ["expr"],         "v0 - int(v0)", False, True), #XXX
+    ("float_integer_part",    ["expr"],         "int(v0)", False, True),
 ]
 
-for prolog_name, unwrap_spec, pattern, overflow in simple_functions:
-    f = wrap_builtin_operation(pattern, unwrap_spec, overflow)
+for prolog_name, unwrap_spec, pattern, overflow, intversion in simple_functions:
+    # the name is purely for flowgraph viewing reasons
+    if prolog_name.replace("_", "").isalnum():
+        name = prolog_name
+    else:
+        import unicodedata
+        name = "".join([unicodedata.name(unicode(c)).replace(" ", "_").replace("-", "").lower() for c in prolog_name])
+    f = wrap_builtin_operation(name, pattern, unwrap_spec, overflow,
+                               intversion)
     signature = "%s/%s" % (prolog_name, len(unwrap_spec))
     arithmetic_functions[signature] = f

Modified: pypy/dist/pypy/lang/prolog/interpreter/error.py
==============================================================================
--- pypy/dist/pypy/lang/prolog/interpreter/error.py	(original)
+++ pypy/dist/pypy/lang/prolog/interpreter/error.py	Thu May 24 16:30:14 2007
@@ -25,8 +25,6 @@
     def __init__(self, continuation):
         self.continuation = continuation
 
-    pass
-
 def throw_instantiation_error():
     from pypy.lang.prolog.interpreter import term
     raise CatchableError(term.Atom.newatom("instantiation_error"))

Modified: pypy/dist/pypy/lang/prolog/interpreter/helper.py
==============================================================================
--- pypy/dist/pypy/lang/prolog/interpreter/helper.py	(original)
+++ pypy/dist/pypy/lang/prolog/interpreter/helper.py	Thu May 24 16:30:14 2007
@@ -36,7 +36,7 @@
     if isinstance(obj, term.Number):
         return obj.num
     elif isinstance(obj, term.Float):
-        f = obj.num; i = int(f)
+        f = obj.floatval; i = int(f)
         if f == i:
             return i
     error.throw_type_error('integer', obj)
@@ -74,6 +74,6 @@
     elif isinstance(obj, term.Number):
         return str(obj.num)
     elif isinstance(obj, term.Float):
-        return str(obj.num)
+        return str(obj.floatval)
     error.throw_type_error("atomic", obj)
 

Modified: pypy/dist/pypy/lang/prolog/interpreter/parsing.py
==============================================================================
--- pypy/dist/pypy/lang/prolog/interpreter/parsing.py	(original)
+++ pypy/dist/pypy/lang/prolog/interpreter/parsing.py	Thu May 24 16:30:14 2007
@@ -321,7 +321,7 @@
             if isinstance(child, Number):
                 return Number(factor * child.num)
             if isinstance(child, Float):
-                return Float(factor * child.num)
+                return Float(factor * child.floatval)
         return Term(name, children)
 
     def build_list(self, node):
@@ -391,7 +391,7 @@
             if isinstance(result, Number):
                 return Number(-result.num)
             elif isinstance(result, Float):
-                return Float(-result.num)
+                return Float(-result.floatval)
         return self.visit(node.children[1])
 
     def visit_listexpr(self, node):

Modified: pypy/dist/pypy/lang/prolog/interpreter/term.py
==============================================================================
--- pypy/dist/pypy/lang/prolog/interpreter/term.py	(original)
+++ pypy/dist/pypy/lang/prolog/interpreter/term.py	Thu May 24 16:30:14 2007
@@ -318,12 +318,12 @@
     TAG = tag()
     STANDARD_ORDER = 2
     _immutable_ = True
-    def __init__(self, num):
-        self.num = num
+    def __init__(self, floatval):
+        self.floatval = floatval
 
     @specialize.arg(3)
     def basic_unify(self, other, heap, occurs_check=False):
-        if isinstance(other, Float) and other.num == self.num:
+        if isinstance(other, Float) and other.floatval == self.floatval:
             return
         raise UnificationFailed
 
@@ -332,22 +332,22 @@
 
     def copy_and_basic_unify(self, other, heap, memo):
         hint(self, concrete=True)
-        if isinstance(other, Float) and other.num == self.num:
+        if isinstance(other, Float) and other.floatval == self.floatval:
             return self
         else:
             raise UnificationFailed
 
     def get_unify_hash(self, heap):
         #XXX no clue whether this is a good idea...
-        m, e = math.frexp(self.num)
+        m, e = math.frexp(self.floatval)
         m = intmask(int(m / 2 * 2 ** (32 - TAGBITS)))
         return intmask(m << TAGBITS | self.TAG)
 
     def __str__(self):
-        return repr(self.num)
+        return repr(self.floatval)
 
     def __repr__(self):
-        return "Float(%r)" % (self.num, )
+        return "Float(%r)" % (self.floatval, )
 
 class BlackBox(NonVar):
     # meant to be subclassed
@@ -589,10 +589,10 @@
         if isinstance(obj2, Number):
             return rcmp(obj1.num, obj2.num)
         elif isinstance(obj2, Float):
-            return rcmp(obj1.num, obj2.num)
+            return rcmp(obj1.num, obj2.floatval)
     if isinstance(obj1, Float):
         if isinstance(obj2, Number):
-            return rcmp(obj1.num, obj2.num)
+            return rcmp(obj1.floatval, obj2.num)
         elif isinstance(obj2, Float):
-            return rcmp(obj1.num, obj2.num)
+            return rcmp(obj1.floatval, obj2.floatval)
     assert 0

Modified: pypy/dist/pypy/lang/prolog/interpreter/test/test_parsing.py
==============================================================================
--- pypy/dist/pypy/lang/prolog/interpreter/test/test_parsing.py	(original)
+++ pypy/dist/pypy/lang/prolog/interpreter/test/test_parsing.py	Thu May 24 16:30:14 2007
@@ -94,7 +94,7 @@
     facts = builder.build(t)
     assert len(facts) == 2
     assert facts[0].args[1].num == -1
-    assert facts[1].args[1].num == -1.345
+    assert facts[1].args[1].floatval == -1.345
     t = parse_file("""
         X = -1.
         arg(X, h(a, b, c), b), X = 2.



More information about the Pypy-commit mailing list