Pierre Carbonnelle avatar Pierre Carbonnelle committed 5de52f7

support in-line queries by using create_atoms()

Comments (0)

Files changed (3)

pyDatalog/examples/test.py

 
     assert (Z.len[X]==Y) == [(w, 1), (z, 1)]
     assert (Z.len[z]==Y) == [(1,)]
+    
+    # TODO print (A.b[w]==Y)
             
     """ python resolvers                                              """
     
     print (result)
     """
     
+if __name__ == "__main__":
+    test()
+    #cProfile.runctx('test()', globals(), locals())
+    
+    """ In-line queries using create_atoms                    """
+    
+    pyDatalog.create_atoms('p', 'Y')
+    +p('a')
+    
+    p(Y)
+    assert (Y._value() == ['a',])
+    
+    X = pyDatalog.Variable()
+    pyDatalog.create_atoms('X')
+    p(X) & (X=='b')
+    assert (X._value() == [])
+    
+    pyDatalog.create_atoms('p2')
+    
+    def test2():
+        p2(X) <= p(X)
+        p2(X)
+        assert (X._value() == ['a',])
+        assert (p2(X) == [('a',)])
+    test2()
+    
     print("Test completed successfully.")
 
-if __name__ == "__main__":
-    test()
-    #cProfile.runctx('test()', globals(), locals())
+    

pyDatalog/pyDatalog.py

 from collections import defaultdict
 import inspect
 import six
+import string
 import sys
 import weakref
 
     def __str__(self):
         return str(set(self.answers))
 
+def create_atoms(*args):
+    stack = inspect.stack()
+    try:
+        locals_ = stack[1][0].f_locals
+        for arg in args:
+            if arg in locals_ and not isinstance(locals_[arg], (pyParser.Symbol, pyDatalog.Variable)):
+                raise BaseException("Name conflict.  Can't redefine %s as atom" % arg)
+            if arg[0] not in string.ascii_uppercase:
+                locals_[arg] = pyParser.Symbol(arg)
+            else:
+                locals_[arg] = pyDatalog.Variable()    
+    finally:
+        del stack
+
 def variables(n):
     return [pyDatalog.Variable() for i in range(n)]
 

pyDatalog/pyParser.py

 * add_program(func)
 * ask(code)
 
-Classes hierarchy contained in this file:
+Classes hierarchy contained in this file: see class diagram on http://bit.ly/YRnMPH
 * ProgramContext : class to safely differentiate between In-line queries and pyDatalog program / ask(), using ProgramMode global variable
 * _transform_ast : performs some modifications of the abstract syntax tree of the datalog program
 * LazyList : a subclassable list that is populated when it is accessed. Mixin for pyDatalog.Variable.
         self.prearity = prearity or len(terms)
         self.pre_calculations = Body()
         
-        # TODO cleanup by redifining self.args, .HasSymbols, .hasVariables, .prefix
-        if not ProgramMode: # in-line, thus
+        self.has_variables, self.has_symbols, self.is_fact = (False, False, True)
+        for t in terms:
+            self.has_variables = self.has_variables or isinstance(t, pyDatalog.Variable)
+            self.has_symbols = self.has_symbols or isinstance(t, Symbol)
+            self.is_fact = self.is_fact and not(isinstance(t, pyDatalog.Variable) and not(isinstance(t, Symbol) and t._pyD_type == 'variable'))
+        
+        # TODO cleanup by redefining self.args, .HasSymbols, .has_variables, .prefix
+        if not ProgramMode: # in-line, thus.  --> replace variables in terms by Symbols
             self.todo = self
             self.args = terms
-            cls = self.predicate_name.split('.')[0] if 1< len(self.predicate_name.split('.')) else ''
+            cls_name = predicate_name.split('.')[0].replace('~','') if 1< len(predicate_name.split('.')) else ''
             terms, env = [], {}
             for i, arg in enumerate(self.args):
                 if isinstance(arg, pyDatalog.Variable):
                     terms.append(variable)
                 elif isinstance(arg, Symbol):
                     terms.append(arg)
-                elif i==0 and cls and arg.__class__.__name__ != cls.replace('~',''):
+                elif i==0 and cls_name and arg.__class__.__name__ != cls_name: # TODO use __mro__ !
                     raise TypeError("Object is incompatible with the class that is queried.")
                 else:
                     terms.append(arg)
 
     def __pos__(self):
         " unary + means insert into database as fact "
-        global ProgramMode
-        assert ProgramMode, "'+' cannot be used to assert facts in python programs"
+        assert self.is_fact, "Cannot assert a fact containing Variables"
         pyDatalog._assert_fact(self)
 
     def __neg__(self):
         " unary - means retract fact from database "
-        assert not self.args # '-' cannot be used with literal containing pyDatalog.Variable instances
+        assert self.is_fact, "Cannot assert a fact containing Variables"
         pyDatalog._retract_fact(self)
         
     def __invert__(self):
         self.literals = []
         for arg in args:
             self.literals += [arg] if isinstance(arg, Literal) else arg.literals
-        self.hasVariables = False
+        self.has_variables = False
         for literal in self.literals:
             if hasattr(literal, 'args'):
-                self.hasVariables = True
+                self.has_variables = True
                 self.todo = self
                 for arg in literal.args:
                     if isinstance(arg, pyDatalog.Variable):
         return Body(self, body2)
     
     def __str__(self):
-        if self.hasVariables:
+        if self.has_variables:
             return LazyListOfList.__str__(self)
         return ' & '.join(list(map (str, self.literals)))
 
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.