Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

an additional fix related to issue #2, as well as made a few other co…

…ding tweaks.
  • Loading branch information...
commit a2f7877c16c7a80d650cda23186f4d3cbf92810e 1 parent 5ec9477
nemonik authored
View
8 .settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,8 @@
+eclipse.preferences.version=1
+encoding//dist/Intellect-1.4.1/intellect/Intellect.py=utf-8
+encoding//intellect/Callable.py=utf-8
+encoding//intellect/IO.py=utf-8
+encoding//intellect/Intellect.py=utf-8
+encoding//intellect/Node.py=utf-8
+encoding//intellect/PolicyLexer.py=utf-8
+encoding//intellect/PolicyTokenSource.py=utf-8
View
15 intellect/Callable.py
@@ -1,3 +1,6 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
'''
Copyright (c) 2011, The MITRE Corporation.
All rights reserved.
@@ -28,13 +31,9 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''
-'''
-Created on May 20, 2011
-
-@author: Michael Joseph Walsh
-'''
class Callable(object):
+
'''
A decorator used to confer to Policy object what
methods are callable.
@@ -44,15 +43,15 @@ def __init__(self, method):
'''
Callable Initializer
'''
- self.__method = method
+ self.__method = method
def __call__(self, *args):
'''
Wrapper to the callable method
'''
- return self.__method(*args)
+ return self.__method(*args)
def __get__(self, obj, obj_type):
"""
@@ -64,4 +63,4 @@ def __get__(self, obj, obj_type):
new_method = self.__method.__get__(obj, obj_type)
- return self.__class__(new_method)
+ return self.__class__(new_method)
View
34 intellect/IO.py
@@ -1,3 +1,5 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
"""
Copyright (c) 2011, The MITRE Corporation.
@@ -29,24 +31,13 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
-
-"""
-StdOut
-
-Description:
- Contains all utulity method for capturing stdout.
-
-Initial Version:
- Oct 19, 2011
-
-@author: Michael Joseph Walsh
-"""
-
import os
import sys
import StringIO
+
class RedirectStdError(object):
+
def __init__(self):
self._stderr = StringIO.StringIO()
@@ -57,12 +48,18 @@ def __enter__(self):
return sys.stderr
- def __exit__(self, exc_type, exc_value, traceback):
+ def __exit__(
+ self,
+ exc_type,
+ exc_value,
+ traceback,
+ ):
self._stderr.flush()
sys.stderr = self.save_stderr
class RedirectStdOut(object):
+
def __init__(self):
self._stdout = StringIO.StringIO()
@@ -73,6 +70,11 @@ def __enter__(self):
return sys.stdout
- def __exit__(self, exc_type, exc_value, traceback):
- self._stdout.flush();
+ def __exit__(
+ self,
+ exc_type,
+ exc_value,
+ traceback,
+ ):
+ self._stdout.flush()
sys.stdout = self.save_stdout
View
22 intellect/Intellect.py
@@ -1,3 +1,6 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
"""
Copyright (c) 2011, The MITRE Corporation.
All rights reserved.
@@ -28,19 +31,14 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
-"""
-Intellect
-
-Description: A rules engine
-
-Initial Version: Oct 27, 2010
-
-@author: Michael Joseph Walsh
-"""
-
-import logging, os, re, traceback, sys
+import logging
+import os
+import re
+import traceback
+import sys
-from antlr3 import FileStream, CommonTokenStream, ANTLRStringStream, RecognitionException
+from antlr3 import FileStream, CommonTokenStream, ANTLRStringStream, \
+ RecognitionException
from intellect.grammar.PolicyParser import PolicyParser
from intellect.PolicyLexer import PolicyLexer
View
50 intellect/Node.py
@@ -1,3 +1,6 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
"""
Copyright (c) 2011, The MITRE Corporation.
All rights reserved.
@@ -41,7 +44,11 @@
@author: Michael Joseph Walsh
"""
-import logging, types, collections, keyword, uuid
+import logging
+import types
+import collections
+import keyword
+import uuid
import intellect.reflection as reflection
@@ -54,7 +61,7 @@ class Node(object):
All Policy Domain Specific Language (DSL) Nodes extend this node.
'''
- def __init__(self, children = None, line = None, column = None):
+ def __init__(self, children=None, line=None, column=None):
'''
Node Initializer
'''
@@ -87,7 +94,7 @@ def __str__(self):
return value
- def str_tree(self, text = "", indentCount = 0):
+ def str_tree(self, text="", indentCount=0):
'''
Returns a textual tree representation of the Node and its
children nodes. Used for debugging purposes.
@@ -333,7 +340,7 @@ def append_global(self, object_reference, value):
self.globals[object_reference] = value
- def log(self, msg, name = "intellect", level = logging.DEBUG):
+ def log(self, msg, name="intellect", level=logging.DEBUG):
'''
Logs at the 'level' for the messaged 'msg'
@@ -352,7 +359,7 @@ def log(self, msg, name = "intellect", level = logging.DEBUG):
@staticmethod
- def filter_to_list(type, node, list = None):
+ def filter_to_list(type, node, list=None):
'''
Returns a list of nodes of 'type' parameter found
in the tree who's parent node is the 'node' parameter.
@@ -445,9 +452,9 @@ def __str__(self):
return value
- def __init__(self, children = None, line = None, column = None):
+ def __init__(self, children=None, line=None, column=None):
- super(Policy,self).__init__(children, line, column)
+ super(Policy, self).__init__(children, line, column)
self._intellect = None
self._globals = {}
@@ -656,9 +663,9 @@ class File(Node):
RuleStmt nodes.
'''
- def __init__(self, children = None, line = None, column = None):
+ def __init__(self, children=None, line=None, column=None):
- super(File,self).__init__(children, line, column)
+ super(File, self).__init__(children, line, column)
self._path = None
@@ -711,7 +718,7 @@ def attributeStmts(self):
@staticmethod
- def set_file_on_descendants(node = None, file_node = None):
+ def set_file_on_descendants(node=None, file_node=None):
'''
Sets this node's file property and all its descendants'
file property to file_node.
@@ -846,7 +853,7 @@ def eval(self, policy):
# portion exists.
Result = collections.namedtuple('Result', 'fireThen, matches, objectBinding')
- whenResults = Result(fireThen = True, matches = [], objectBinding = None)
+ whenResults = Result(fireThen=True, matches=[], objectBinding=None)
self.log("When results for '{0}': {1}".format(self.id, whenResults))
@@ -948,6 +955,9 @@ def eval(self, policy, ruleStmt):
localScope["policy"] = policy
localScope["klazz"] = klazz
+ # This is needed because for the reasons documented in reflection.is_instance
+ localScope["reflection"] = reflection.module_from_str("intellect.reflection")
+
# Rewrite the ClassConstraint.constraint
rewrittenConstraint = When.rewrite(classConstraint.constraint, Constraint(), klazz)
@@ -957,7 +967,7 @@ def eval(self, policy, ruleStmt):
# Restrict the list comprehension to just the
# ClassConstraint.name'ed class-type
- code += "isinstance(fact, klazz) and "
+ code += "reflection.is_instance(fact, klazz) and "
# Append 'not' prior to the Constraint, if the negated
code += "not (" if self.ruleCondition.notCondition.is_negated() else ""
@@ -988,7 +998,7 @@ def eval(self, policy, ruleStmt):
self.log("match all the learned objects of ClassConstraint.name'ed class-type")
matches = [fact for fact in policy.intellect.knowledge if reflection.is_instance(fact, klazz)]
else:
- # match all the learned objects that are not the ClassConstraint.name'ed class-type
+ # match all the learned objects that are not the ClassConstraint.name'ed class -type
self.log("match all the learned objects that are not the ClassConstraint.name'ed class-type")
matches = [fact for fact in policy.intellect.knowledge if not reflection.is_instance(fact, klazz)]
@@ -1016,7 +1026,7 @@ def eval(self, policy, ruleStmt):
# The Condition does not hold an Exists token
if not matches:
fireThen = False
- objectBinding= None
+ objectBinding = None
else:
fireThen = True
else:
@@ -1027,7 +1037,7 @@ def eval(self, policy, ruleStmt):
# Create a new named tuple to hold the results
Result = collections.namedtuple('Result', 'fireThen, matches, objectBinding')
- return Result(fireThen = fireThen, matches = matches, objectBinding = objectBinding)
+ return Result(fireThen=fireThen, matches=matches, objectBinding=objectBinding)
@staticmethod
@@ -1057,8 +1067,8 @@ def rewrite(original, rewritten, klazz):
#
# TODO: need a better string then "fact" as this may
# may already be used in the constraint
- power = Power( [Atom( "fact" ), Trailer( [".", child.first_child().first_child()] )] )
- rewritten.append_child( power )
+ power = Power([Atom("fact"), Trailer([".", child.first_child().first_child()])])
+ rewritten.append_child(power)
if (len(child.children) > 1):
for c in child.children[1:]:
@@ -1148,7 +1158,7 @@ def eval(self, policy, ruleStmt, matches, objectBinding):
#
# TODO: use of the identifier "newFact" may
# be a problem down the road...
- code = "new_fact" + " = " + actualAction.name + "(" + (str(actualAction.argList) if actualAction.argList != None else "") +")"
+ code = "new_fact" + " = " + actualAction.name + "(" + (str(actualAction.argList) if actualAction.argList != None else "") + ")"
self.log("Code to be run for learnAction in rule: '{0}' at line: {1} in the policy file: '{2}':\n{3}".format(ruleStmt.id, actualAction.line, self.file.path, code))
@@ -1255,7 +1265,7 @@ def eval(self, policy, ruleStmt, matches, objectBinding):
# create a newObject with the arguments, if provided,
# and append it to learned objects in memory
- code = "new_fact" + " = " + actualAction.name + "(" + (str(actualAction.argList) if actualAction.argList != None else "") +")"
+ code = "new_fact" + " = " + actualAction.name + "(" + (str(actualAction.argList) if actualAction.argList != None else "") + ")"
self.log("Code to be run for learnAction in rule: '{0}' at line: {1} in the policy file: '{2}':\n{3}".format(ruleStmt.id, actualAction.line, self.file.path, code))
@@ -1349,7 +1359,7 @@ def rewrite(original, rewritten, objectBinding):
#
# TODO: need a better string then "match" as this may
# may already be used in the constraint
- rewritten.append_child( Atom("match") )
+ rewritten.append_child(Atom("match"))
else:
# nothing matched to rewrite; so, clone
twin = type(child)()
View
16 intellect/PolicyLexer.py
@@ -1,3 +1,6 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
"""
Copyright (c) 2011, The MITRE Corporation.
All rights reserved.
@@ -28,19 +31,12 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
-"""
-PolicyLexer
-
-Description: Extends the auto generated grammar.PolicyLexer
-
-Initial Version: Feb 16, 2011
-
-@author: Michael Joseph Walsh
-"""
-
from intellect.grammar.PolicyLexer import PolicyLexer as AutoGeneratedLexer
+
class PolicyLexer(AutoGeneratedLexer):
+
def nextToken(self):
self.startPosition = self.getCharPositionInLine()
return AutoGeneratedLexer.nextToken(self)
+
View
111 intellect/PolicyTokenSource.py
@@ -1,3 +1,6 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
"""
Copyright (c) 2004 Terence Parr and Loring Craymer
All rights reserved.
@@ -25,26 +28,15 @@
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
-"""
-PoicyTokenSource
-
-Description: Used to further process tokens
-
-Initial Version: Feb 24, 2011
-
-@author: Michael Joseph Walsh
-
-The code is a slightly modified form of the PythonTokenSource.py
-found at http://www.antlr.org/depot/examples-v3/Python/python/PythonTokenSource.py
-"""
-
from antlr3.tokens import ClassicToken, EOF
from antlr3.recognizers import TokenSource
from intellect.grammar.PolicyParser import INDENT, DEDENT
from intellect.grammar.PolicyLexer import NEWLINE, LEADING_WS
+
class PolicyTokenSource(TokenSource):
+
"""
Python does not explicitly provide begin and end nesting signals.
Rather, the indentation level indicates when you begin and end.
@@ -86,21 +78,25 @@ class PolicyTokenSource(TokenSource):
Terence Parr and Loring Craymer
February 2004
"""
+
FIRST_CHAR_POSITION = 0
def __init__(self, stream):
+
# The stack of indent levels (column numbers)
# "state" of indent level is FIRST_CHAR_POSITION
+
self.indentStack = [self.FIRST_CHAR_POSITION]
-
+
# The queue of tokens
+
self.tokens = []
# We pull real tokens from this lexer
+
self.stream = stream
-
- self.lastTokenAddedIndex = -1
+ self.lastTokenAddedIndex = -1
def nextToken(self):
"""
@@ -126,25 +122,28 @@ def nextToken(self):
EOF to have char pos 0 even though with UNIX it's hard to get EOF
at a non left edge.
"""
-
+
# if something in queue, just remove and return it
+
if len(self.tokens) > 0:
t = self.tokens.pop(0)
return t
-
- self.insertImaginaryIndentDedentTokens();
- return self.nextToken()
+ self.insertImaginaryIndentDedentTokens()
+ return self.nextToken()
def insertImaginaryIndentDedentTokens(self):
t = self.stream.LT(1)
self.stream.consume()
# if not a NEWLINE, doesn't signal indent/dedent work; just enqueue
+
if t.getType() != NEWLINE:
- hiddenTokens = self.stream.getTokens(self.lastTokenAddedIndex + 1, t.getTokenIndex() - 1)
-
+ hiddenTokens = \
+ self.stream.getTokens(self.lastTokenAddedIndex + 1,
+ t.getTokenIndex() - 1)
+
if hiddenTokens is not None:
self.tokens.extend(hiddenTokens)
@@ -153,9 +152,11 @@ def insertImaginaryIndentDedentTokens(self):
return
# save NEWLINE in the queue
- #print "found newline: "+str(t)+" stack is "+self.stackString()
- hiddenTokens = self.stream.getTokens(self.lastTokenAddedIndex + 1, t.getTokenIndex() - 1)
-
+ # print "found newline: "+str(t)+" stack is "+self.stackString()
+
+ hiddenTokens = self.stream.getTokens(self.lastTokenAddedIndex
+ + 1, t.getTokenIndex() - 1)
+
if hiddenTokens is not None:
self.tokens.extend(hiddenTokens)
@@ -163,58 +164,70 @@ def insertImaginaryIndentDedentTokens(self):
self.tokens.append(t)
# grab first token of next line
- t = self.stream.LT(1);
- self.stream.consume();
+
+ t = self.stream.LT(1)
+ self.stream.consume()
# handle hidden tokens
- hiddenTokens = self.stream.getTokens(self.lastTokenAddedIndex + 1, t.getTokenIndex() - 1)
-
+
+ hiddenTokens = self.stream.getTokens(self.lastTokenAddedIndex
+ + 1, t.getTokenIndex() - 1)
+
if hiddenTokens is not None:
self.tokens.extend(hiddenTokens)
self.lastTokenAddedIndex = t.getTokenIndex()
# compute cpos as the char pos of next non-WS token in line
- cpos = t.getCharPositionInLine() # column dictates indent/dedent
-
+
+ cpos = t.getCharPositionInLine() # column dictates indent/dedent
+
if t.getType() == EOF:
- cpos = -1 # pretend EOF always happens at left edge
+ cpos = -1 # pretend EOF always happens at left edge
elif t.getType() == LEADING_WS:
cpos = len(t.getText())
- #print "next token is: "+str(t)
+ # print "next token is: "+str(t)
# compare to last indent level
+
lastIndent = self.indentStack[-1]
- #print "cpos, lastIndent = "+str(cpos)+", "+str(lastIndent)
- if cpos > lastIndent: # they indented; track and gen INDENT
- self.indentStack.append(cpos);
- #print self.indentStack
- #print "push("+str(cpos)+"): "+self.stackString()
- indent = ClassicToken(INDENT, "")
+
+ # print "cpos, lastIndent = "+str(cpos)+", "+str(lastIndent)
+
+ if cpos > lastIndent: # they indented; track and gen INDENT
+ self.indentStack.append(cpos)
+
+ # print self.indentStack
+ # print "push("+str(cpos)+"): "+self.stackString()
+
+ indent = ClassicToken(INDENT, '')
indent.setCharPositionInLine(t.getCharPositionInLine())
indent.setLine(t.getLine())
self.tokens.append(indent)
+ elif cpos < lastIndent:
- elif cpos < lastIndent: # they dedented
+ # they dedented
# how far back did we dedent?
- prevIndex = self.findPreviousIndent(cpos);
- #print "dedented; prevIndex of cpos="+str(cpos)+" is "+str(prevIndex)
+ prevIndex = self.findPreviousIndent(cpos)
+
+ # print "dedented; prevIndex of cpos="+str(cpos)+" is "+str(prevIndex)
# generate DEDENTs for each indent level we backed up over
+
while len(self.indentStack) > prevIndex + 1:
- dedent = ClassicToken(DEDENT, "")
+ dedent = ClassicToken(DEDENT, '')
dedent.setCharPositionInLine(t.getCharPositionInLine())
dedent.setLine(t.getLine())
self.tokens.append(dedent)
- self.indentStack.pop(-1) # pop those off indent level
- #print self.indentStack
+ self.indentStack.pop(-1) # pop those off indent level
- if t.getType() != LEADING_WS: # discard WS
- self.tokens.append(t)
+ # print self.indentStack
+ if t.getType() != LEADING_WS: # discard WS
+ self.tokens.append(t)
# T O K E N S T A C K M E T H O D S
@@ -222,12 +235,12 @@ def findPreviousIndent(self, i):
'''
Return the index on stack of previous indent level == i else -1
'''
- for j, pos in reversed(list(enumerate(self.indentStack))):
+
+ for (j, pos) in reversed(list(enumerate(self.indentStack))):
if pos == i:
return j
return self.FIRST_CHAR_POSITION
-
def stackString(self):
return ' '.join([str(i) for i in reversed(self.indentStack)])
View
2  intellect/__init__.py
@@ -30,4 +30,4 @@
__author__ = "Michael Joseph Walsh"
-VERSION = (1, 4, 8, 2)
+VERSION = (1, 4, 8, 3)
View
77 intellect/examples/testing/Question.py
@@ -0,0 +1,77 @@
+'''
+Created on Apr 25, 2012
+
+@author: walsh
+'''
+import sys, logging
+
+from intellect.Intellect import Intellect
+
+class Person(object):
+ '''
+ An person fact
+ '''
+
+ def __init__(self, nom_de_plume=None, children=None):
+ '''
+ Parent initializer
+ '''
+ self.nom_de_plume = nom_de_plume
+ self.children = children
+
+ print "created an instance of Person w/ nom_de_plume: {0}".format(nom_de_plume)
+
+ @property
+ def nom_de_plume(self):
+ return self._nom_de_plume
+
+ @nom_de_plume.setter
+ def nom_de_plume(self, value):
+ self._nom_de_plume = value
+
+ @property
+ def children(self):
+ return self._children
+
+ @children.setter
+ def children(self, value):
+ self._children = value
+
+
+if __name__ == '__main__':
+
+ # tune down logging inside Intellect
+ logger = logging.getLogger('intellect')
+ logger.setLevel(logging.ERROR)
+ consoleHandler = logging.StreamHandler(stream=sys.stdout)
+ consoleHandler.setFormatter(logging.Formatter('%(asctime)s %(name)-12s %(levelname)-8s%(message)s'))
+ logger.addHandler(consoleHandler)
+
+ Mary = Person('Mary')
+ Bob = Person('Bob')
+ Michael = Person('Michael')
+ David = Person('David', {Mary, Bob, Michael})
+
+ intellect = Intellect()
+
+ intellect.learn(David);
+
+ try:
+ policy = intellect.learn('''
+from intellect.examples.testing.Question import Person
+
+rule mary_is_a_child:
+ when:
+ $person := Person( children and filter(lambda x: x.nom_de_plume == 'Mary', David.children))
+ then:
+ print("Person with a child Mary found")
+
+''')
+ except Exception, err:
+ print "This fails because the grammar doesn't support 'lambda' to keep things comprehensible, but I can modify the grammar..."
+ sys.exit
+
+ intellect.policy.str_tree("sytnax", 2)
+
+ intellect.reason()
+
View
9 intellect/reflection.py
@@ -411,6 +411,15 @@ def module_from_string(moduleName, policy):
return module
+def module_from_str(name):
+ '''
+ Returns a Module object from dottedName.identifier str such as
+ 'intellect.reflection'.
+ '''
+ module = sys.modules[name]
+
+ log("returning {0} for {1}".format(module, name))
+ return module
def class_from_str(name):
'''

1 comment on commit a2f7877

@nemonik
Owner

Actually this fix wasn't related to issue #2 but another issue not recorded in Issues...

Please sign in to comment.
Something went wrong with that request. Please try again.