configurationengine/source/plugins/common/ConeLegacyRulePlugin/legacyruleplugin/rules.py
author m2lahtel
Tue, 10 Aug 2010 14:29:28 +0300
changeset 3 e7e0ae78773e
permissions -rw-r--r--
ConE 1.2.11 release
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
3
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
     1
#
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
     2
# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
     3
# All rights reserved.
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
     4
# This component and the accompanying materials are made available
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
     5
# under the terms of "Eclipse Public License v1.0"
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
     6
# which accompanies this distribution, and is available
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
     7
# at the URL "http://www.eclipse.org/legal/epl-v10.html".
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
     8
#
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
     9
# Initial Contributors:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    10
# Nokia Corporation - initial contribution.
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    11
#
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    12
# Contributors:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    13
#
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    14
# Description: 
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    15
# 
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    16
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    17
import operator as ops
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    18
import logging
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    19
import tokenize
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    20
from token import ENDMARKER, NAME, ERRORTOKEN
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    21
import StringIO
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    22
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    23
from cone.public import container
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    24
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    25
RELATIONS = {}
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    26
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    27
def abstract():
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    28
    import inspect
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    29
    caller = inspect.getouterframes(inspect.currentframe())[1][3]
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    30
    raise NotImplementedError(caller + ' needs to be implemented')
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    31
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    32
def get_tokens(tokenstr):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    33
    result = []
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    34
    tokens = []
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    35
    tokenstr = tokenstr.replace('\r', '')
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    36
    name_buffer = [] # Temp buffer for reading name tokens
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    37
    last_epos = None
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    38
    for toknum, tokval, spos, epos, _  in tokenize.generate_tokens(StringIO.StringIO(unicode(tokenstr)).readline):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    39
        #print "toknum: %r, tokval: %r, spos: %r, epos: %r" % (toknum, tokval, spos, epos)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    40
        val = tokval.strip('\r\n\t ')
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    41
        
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    42
        if toknum == ENDMARKER and name_buffer:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    43
            tokens.append(''.join(name_buffer))
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    44
        
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    45
        # Ignore whitespace (this ignores also the end marker,
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    46
        # since its value is empty)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    47
        if val == '': continue
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    48
        
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    49
        # Put NAME, and ERRORTOKEN tokens through the temp
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    50
        # buffer
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    51
        if toknum in (NAME, ERRORTOKEN):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    52
            # If this and the previous token in the temp buffer are not adjacent,
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    53
            # they belong to separate tokens
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    54
            if name_buffer and spos[1] != last_epos[1]:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    55
                tokens.append(''.join(name_buffer))
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    56
                name_buffer = []
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    57
            
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    58
            name_buffer.append(val)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    59
            last_epos = epos
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    60
        # Other tokens can just go directly to the token list
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    61
        else:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    62
            if name_buffer:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    63
                tokens.append(''.join(name_buffer))
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    64
                name_buffer = []
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    65
            tokens.append(val)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    66
    
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    67
    while len(tokens) > 0:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    68
        val = tokens.pop(0)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    69
        # Join the refs with dot in between them to make them dotted refs
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    70
        if val == '.':
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    71
            newval = ".".join([result.pop(),tokens.pop(0)])
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    72
            result.append( newval )
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    73
        else:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    74
            result.append( val )
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    75
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    76
    return result
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    77
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    78
class RelationException(Exception):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    79
    pass
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    80
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    81
#### The containers are here ####
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    82
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    83
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    84
class RelationBase(object):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    85
    """
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    86
    RelationBase defines a base class for all named relations that can be applied between objects. 
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    87
    e.g. Relation depends, that can be applied in Rule
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    88
    """
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    89
    relation_name = "RelationBase"
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    90
    def __init__(self, data, left, right):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    91
        self.description = ""
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    92
        self.data = data or container.DataContainer()
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    93
        self.left = left
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    94
        self.right = right
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    95
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    96
    def __str__(self):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    97
        """
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    98
        @return: A string presentation of the relation object
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
    99
        """
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   100
        return "%s %s %s" % (self.left,self.relation_name,self.right)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   101
    
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   102
    def __repr__(self):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   103
        return "%s(ref=%r, lineno=%r)" % (self.__class__.__name__,
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   104
                                          getattr(self, 'ref', None),
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   105
                                          getattr(self, 'lineno', None))
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   106
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   107
    def get_name(self):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   108
        """
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   109
        @return: The relation name.
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   110
        """
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   111
        return self.relation_name
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   112
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   113
    def get_description(self):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   114
        """
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   115
        @return: a possible description of the relation.
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   116
        """
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   117
        return self.description
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   118
        
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   119
    def execute(self):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   120
        """
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   121
        Execute the relation object.
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   122
        """
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   123
        pass
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   124
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   125
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   126
class RelationContainer(RelationBase, list):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   127
    """
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   128
    This class provides the RelationContainer interface for collecting
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   129
    relation sets into one place which can be executed through the container.
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   130
    """
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   131
    def __init__(self, data=None):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   132
        super(RelationContainer, self).__init__(data, 'LContainer', 'RContainer')
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   133
        self.value_list = list()
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   134
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   135
    def append(self, value):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   136
        self.value_list.append(value)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   137
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   138
    def __iter__(self):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   139
        return self.value_list.__iter__()
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   140
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   141
    def __len__(self):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   142
        return len(self.value_list)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   143
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   144
    def __or__(self, other):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   145
        """
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   146
        This function adds two RelationContainers to each other and removes
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   147
        duplicates from the result.
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   148
        The modification is inplace and the returned value is called object.
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   149
        """
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   150
        self.value_list = set(self.value_list) | set(other.value_list)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   151
        return self
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   152
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   153
    def __unicode__(self):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   154
        if self:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   155
            ret = ''
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   156
            for value in self:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   157
                ret += unicode(value)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   158
        else:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   159
            ret = 'No relations'
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   160
        return ret
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   161
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   162
    def find_relations(self, refs): abstract()
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   163
    def add_relation(self, relation): abstract()
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   164
    def has_errors(self): abstract()
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   165
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   166
class RelationContainerImpl(RelationContainer):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   167
    """ Base implementation for RelationContainer to use in ConE rules
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   168
    """
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   169
    def execute(self):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   170
        ret = True
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   171
        i = 0
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   172
        for relation in self:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   173
            i += 1
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   174
            r = relation.execute()
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   175
            ret = ret and r
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   176
        return ret
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   177
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   178
    def find_relations(self, refs):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   179
        relations = []
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   180
        for ref in refs:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   181
            for relation in self:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   182
                if relation.has_ref(ref):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   183
                    relations.append(relation)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   184
        return relations
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   185
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   186
    def add_relation(self, relation):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   187
        self.append(relation)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   188
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   189
    def has_ref(self, refs):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   190
        for ref in refs:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   191
            for relation in self:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   192
                if relation.has_ref(ref):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   193
                    return True
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   194
        return False
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   195
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   196
    def has_errors(self):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   197
        for relation in self:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   198
            if relation.has_errors():
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   199
                return True
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   200
        return False
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   201
            
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   202
    def get_errors(self):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   203
        errors = []
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   204
        for relation in self:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   205
            errors += relation.get_errors()
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   206
        return errors
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   207
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   208
#### The relations are here ####
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   209
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   210
class BaseRelation(RelationBase):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   211
    """ BaseRelation implements the basic evaluation logic for relations
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   212
    This class abstract and should be extended for concrete implementation of
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   213
    relation type.
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   214
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   215
    Subclasses need to set their own context in their constructor before this
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   216
    class's constructor is called if custom context is needed. If context not
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   217
    set then DefaultContext is used.
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   218
    """
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   219
    KEY = 'base_relation'
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   220
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   221
    def __init__(self, data, left, right):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   222
        # Context needs to be overridden for special purposes
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   223
        try:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   224
            self.__getattribute__('context')
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   225
        except AttributeError:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   226
            self.context = DefaultContext(data)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   227
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   228
        left = self.expand_rule_elements(left)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   229
        right = self.expand_rule_elements(right)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   230
        super(BaseRelation, self).__init__(data, left, right)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   231
        self.interpreter = ASTInterpreter(context=self.context)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   232
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   233
    def execute(self, context=None):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   234
        """
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   235
        @return Returns error dictionary
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   236
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   237
        In the client code proper way to check if the rule applies:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   238
        info = relation.execute()
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   239
        if not info.has_errors():
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   240
        else: HANDLE ERRORS
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   241
        """
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   242
        # logger.debug("Interpreter context %s" % self.interpreter.context)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   243
        self.interpreter.create_ast('%s %s %s' % (self.left, self.KEY, self.right))
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   244
        ret = self.interpreter.eval(context, relation=self)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   245
        return ret
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   246
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   247
    def get_keys(self):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   248
        """ Returns the references from this relation.
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   249
        """
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   250
        refs = ASTInterpreter.extract_refs(self.left)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   251
        refs += ASTInterpreter.extract_refs(self.right)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   252
        return refs
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   253
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   254
    def has_ref(self, ref):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   255
        """ Returns if the 'ref' is included in this relation
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   256
        """
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   257
        return ref in self.get_keys()
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   258
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   259
    def has_errors(self):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   260
        return bool(self.interpreter.errors)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   261
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   262
    def get_refs(self):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   263
        extracted_refs = ASTInterpreter.extract_refs(self.left)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   264
        
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   265
        # Handle eval expressions (a somewhat ugly hack,
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   266
        # but this is a legacy plug-in so...)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   267
        interpreter = ASTInterpreter(self.left)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   268
        for expression in interpreter.parse_tree:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   269
            if hasattr(expression, 'extract_refs'):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   270
                extracted_refs.extend(expression.extract_refs())
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   271
        
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   272
        # Filter out entries that evaluate successfully as Python code
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   273
        # e.g. True or 123
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   274
        result = []
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   275
        for item in extracted_refs:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   276
            try:    eval(item)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   277
            except: result.append(item)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   278
            else:   pass
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   279
        return result
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   280
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   281
    def _eval_rside_value(self, value): abstract()
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   282
    def _compare_value(self, value): abstract()
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   283
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   284
    def extract_erroneus_features_with_values(self):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   285
        """
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   286
        Extract references who have errors.
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   287
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   288
        Returns dictionary { 'reference' : 'value' }
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   289
        """
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   290
        data_dict = {}
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   291
        for ref in ASTInterpreter.extract_refs(self.right):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   292
            value = self.data.get_feature(ref)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   293
            if self._compare_value(value):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   294
                data_dict[ref] = value
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   295
            elif value == None:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   296
                data_dict[ref] = None
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   297
        return data_dict
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   298
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   299
    def get_errors(self):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   300
        return self.interpreter.errors
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   301
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   302
    def expand_rule_elements(self, rule):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   303
        """ Expans rule elements base on the reference.
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   304
        Context is used for fetching the child elements for parent references
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   305
        which uses asterisk identifier for selecting all child features: 
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   306
        'parent_feature.*' -> 'child_fea_1 and child_fea_2'.
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   307
        """
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   308
        tokens = get_tokens(rule) # [token for token in rule.split()]
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   309
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   310
        expanded_rule = ""
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   311
        for token in tokens:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   312
            if token.endswith('.*'):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   313
                index = token.index('.*')
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   314
                parent_ref = token[:index]
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   315
                children = self.context.get_children_for_reference(parent_ref)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   316
                expanded_element = ' and '.join([child.reference for child in children])
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   317
                if expanded_rule:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   318
                    expanded_rule = '%s and %s' % (expanded_rule, expanded_element.rstrip())
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   319
                else:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   320
                    expanded_rule = expanded_element.rstrip()
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   321
            elif token.lower() in OPERATORS:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   322
                expanded_rule += ' %s ' % token
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   323
            else:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   324
                if expanded_rule:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   325
                    expanded_rule += '%s'% token
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   326
                else:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   327
                    expanded_rule = token
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   328
        return expanded_rule.strip()
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   329
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   330
class RequireRelation(BaseRelation):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   331
    KEY = 'requires'
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   332
RELATIONS[RequireRelation.KEY] = RequireRelation
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   333
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   334
class ExcludesRelation(BaseRelation):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   335
    KEY = 'excludes'
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   336
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   337
RELATIONS['excludes'] = ExcludesRelation
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   338
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   339
################################
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   340
# Abstract syntax tree builder #
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   341
################################
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   342
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   343
def nor(expression, a, b):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   344
    return not ops.or_(a, b)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   345
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   346
def nand(expression, a, b):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   347
    return not ops.and_(a, b)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   348
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   349
def truth_and(expression, a, b):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   350
    return ops.truth(a) and ops.truth(b)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   351
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   352
class DefaultContext(object):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   353
    """ DefaultContext implements ConE specific context for handling rules
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   354
    """
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   355
    def __init__(self, data):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   356
        self.data = data
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   357
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   358
    def eval(self, ast, expression, value):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   359
        pass
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   360
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   361
    def get_keys(self, refs):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   362
        return ASTInterpreter.extract_refs(refs)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   363
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   364
    def get_children_for_reference(self, reference):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   365
        # implement ConE specific children expansion
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   366
        pass
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   367
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   368
    def handle_terminal(self, expression):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   369
        try:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   370
            return int(expression)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   371
        except:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   372
            return expression
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   373
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   374
PRECEDENCES = {
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   375
    'PREFIX_OPERATORS' : 10,
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   376
    'MULDIV_OPERATORS' : 8,
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   377
    'ADDSUB_OPERATORS' : 7,
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   378
    'SHIFT_OPERATORS' : 6,
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   379
    'BITWISE_OPERATORS' : 5,
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   380
    'COMPARISON_OPERATORS' : 4,
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   381
    'SET_OPERATORS' : 3,
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   382
    'BOOLEAN_OPERATORS' : 2, 
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   383
    'RELATION_OPERATORS' : 1,
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   384
    'NOT_DEFINED' : 0
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   385
}
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   386
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   387
class Expression(object):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   388
    PRECEDENCE = PRECEDENCES['NOT_DEFINED']
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   389
    KEY = 'base_expression'
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   390
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   391
    def __init__(self, ast):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   392
        self.ast = ast
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   393
        self.value = None
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   394
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   395
    def get_title(self):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   396
        return self.KEY
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   397
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   398
    def eval(self, context, **kwargs): pass
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   399
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   400
class OneParamExpression(Expression):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   401
    PARAM_COUNT = 1
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   402
    def __init__(self, ast, expression):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   403
        super(OneParamExpression, self).__init__(ast)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   404
        self.expression = expression
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   405
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   406
    def __unicode__(self):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   407
        return u'%s %s' % (self.KEY, self.expression)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   408
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   409
    def eval(self, context, **kwargs):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   410
        self.value = self.OP(self.expression.eval(context, **kwargs))
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   411
        context.eval(self.ast, self, self.value)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   412
        return self.value
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   413
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   414
class TwoOperatorExpression(Expression):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   415
    PARAM_COUNT = 2
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   416
    OP = None
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   417
    EVAL_AS_BOOLS = True
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   418
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   419
    def __init__(self, ast, left, right):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   420
        super(TwoOperatorExpression, self).__init__(ast)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   421
        self.left = left
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   422
        self.right = right
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   423
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   424
    def __unicode__(self):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   425
        return u'%s %s %s' % (self.left, self.KEY, self.right)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   426
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   427
    def eval(self, context, **kwargs):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   428
        self.value = self.OP(self.left.eval(context, **kwargs), self.right.eval(context, **kwargs))
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   429
        context.eval(self.ast, self, self.value)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   430
        return self.value
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   431
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   432
class TwoOperatorBooleanExpression(TwoOperatorExpression):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   433
    def eval(self, context, **kwargs):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   434
        self.value = self.OP(bool(self.left.eval(context, **kwargs)), bool(self.right.eval(context, **kwargs)))
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   435
        context.eval(self.ast, self, self.value)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   436
        return self.value         
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   437
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   438
class TerminalExpression(Expression):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   439
    KEY = 'terminal'
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   440
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   441
    def __init__(self, ast, expression):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   442
        super(TerminalExpression, self).__init__(ast)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   443
        self.expression = expression
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   444
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   445
    def eval(self, context, **kwargs):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   446
        """ Use context to eval the value
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   447
        Expression on TerminalExpression is feature reference or value
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   448
        context should handle the reference conversion to correct value
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   449
        """
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   450
        from cone.public import exceptions
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   451
        try:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   452
            context.configuration.get_default_view().get_feature(self.expression)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   453
            self.value = context.handle_terminal(self.expression)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   454
        except exceptions.NotFound:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   455
            self.value = context.convert_value(self.expression)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   456
            
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   457
        return self.value
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   458
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   459
    def __unicode__(self):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   460
        return self.expression
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   461
    
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   462
    def __repr__(self):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   463
        return self.expression
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   464
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   465
    def get_ref(self):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   466
        """
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   467
        @return: The setting reference, e.g. 'MyFeature.MySetting'
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   468
        """
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   469
        return self.expression
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   470
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   471
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   472
class NegExpression(OneParamExpression):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   473
    PRECEDENCE = PRECEDENCES['PREFIX_OPERATORS']
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   474
    KEY= '-'
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   475
    OP = ops.neg
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   476
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   477
class AndExpression(TwoOperatorBooleanExpression):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   478
    PRECEDENCE = PRECEDENCES['BOOLEAN_OPERATORS']
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   479
    KEY= 'and'
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   480
    OP = truth_and
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   481
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   482
class NandExpression(TwoOperatorBooleanExpression):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   483
    PRECEDENCE = PRECEDENCES['BOOLEAN_OPERATORS']
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   484
    KEY = 'nand'
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   485
    OP = nand
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   486
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   487
class OrExpression(TwoOperatorBooleanExpression):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   488
    PRECEDENCE = PRECEDENCES['BOOLEAN_OPERATORS']
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   489
    KEY = 'or'
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   490
    OP = ops.or_
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   491
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   492
class XorExpression(TwoOperatorBooleanExpression):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   493
    PRECEDENCE = PRECEDENCES['BOOLEAN_OPERATORS']
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   494
    KEY = 'xor'
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   495
    OP = ops.xor
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   496
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   497
class NorExpression(TwoOperatorBooleanExpression):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   498
    PRECEDENCE = PRECEDENCES['BOOLEAN_OPERATORS']
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   499
    KEY = 'nor'
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   500
    OP = nor
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   501
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   502
class EqualExpression(TwoOperatorExpression):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   503
    PRECEDENCE = PRECEDENCES['COMPARISON_OPERATORS']
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   504
    KEY = '=='
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   505
    OP = ops.eq
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   506
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   507
class NotEqualExpression(TwoOperatorExpression):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   508
    PRECEDENCE = PRECEDENCES['COMPARISON_OPERATORS']
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   509
    KEY = '!='
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   510
    OP = ops.ne
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   511
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   512
class LessThanExpression(TwoOperatorExpression):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   513
    PRECEDENCE = PRECEDENCES['COMPARISON_OPERATORS']
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   514
    KEY = '<'
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   515
    OP = ops.lt
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   516
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   517
class GreaterThanExpression(TwoOperatorExpression):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   518
    PRECEDENCE = PRECEDENCES['COMPARISON_OPERATORS']
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   519
    KEY = '>'
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   520
    OP = ops.gt
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   521
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   522
class LessThanEqualExpression(TwoOperatorExpression):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   523
    PRECEDENCE = PRECEDENCES['COMPARISON_OPERATORS']
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   524
    KEY = '<='
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   525
    OP = ops.le
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   526
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   527
class GreaterThanEqualExpression(TwoOperatorExpression):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   528
    PRECEDENCE = PRECEDENCES['COMPARISON_OPERATORS']
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   529
    KEY = '>='
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   530
    OP = ops.ge
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   531
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   532
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   533
def handle_require(expression, left, right):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   534
    if left and right:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   535
        return True
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   536
    elif not left:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   537
        return True
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   538
    return False
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   539
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   540
class RequireExpression(TwoOperatorExpression):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   541
    PRECEDENCE = PRECEDENCES['RELATION_OPERATORS']
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   542
    KEY = 'requires'
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   543
    OP = handle_require
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   544
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   545
    def eval(self, context, **kwargs):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   546
        super(RequireExpression, self).eval(context, **kwargs)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   547
        if not self.value:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   548
            left_keys = []
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   549
            for ref in self.ast.extract_refs(unicode(self.left)):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   550
                for key in context.get_keys(ref):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   551
                    left_keys.append(key)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   552
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   553
            for key in left_keys:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   554
                self.ast.add_error(key, { 'error_string' : 'REQUIRES right side value is "False"',
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   555
                                          'left_key' : key,
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   556
                                          'rule' : self.ast.expression
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   557
                                          })
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   558
        return self.value
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   559
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   560
def handle_exclude(expression, left, right):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   561
    if left and not right:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   562
        return True
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   563
    elif not left:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   564
        return True
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   565
    return False
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   566
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   567
class ExcludeExpression(TwoOperatorExpression):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   568
    PRECEDENCE = PRECEDENCES['RELATION_OPERATORS']
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   569
    KEY = 'excludes'
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   570
    OP = handle_exclude
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   571
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   572
    def eval(self, context, **kwargs):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   573
        super(ExcludeExpression, self).eval(context, **kwargs)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   574
        if not self.value:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   575
            left_keys = []
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   576
            for ref in self.ast.extract_refs(unicode(self.left)):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   577
                for key in context.get_keys(ref):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   578
                    left_keys.append(key)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   579
                    
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   580
            for key in left_keys:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   581
                self.ast.add_error(key, { 'error_string' : 'EXCLUDE right side value is "True"',
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   582
                                          'left_key' : key,
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   583
                                          'rule' : self.ast.expression
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   584
                                          })
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   585
        return self.value
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   586
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   587
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   588
class NotExpression(OneParamExpression):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   589
    PRECEDENCE = PRECEDENCES['PREFIX_OPERATORS']
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   590
    KEY = 'not'
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   591
    OP = ops.not_
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   592
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   593
class TruthExpression(OneParamExpression):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   594
    PRECEDENCE = PRECEDENCES['PREFIX_OPERATORS']
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   595
    KEY = 'truth'
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   596
    OP = ops.truth
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   597
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   598
LEFT_PARENTHESIS = '('
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   599
RIGHT_PARENTHESIS = ')'
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   600
class SimpleCondition(EqualExpression):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   601
    """
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   602
    A simple condition object that can refer to a model object and evaluate if the value matches  
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   603
    """
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   604
    def __init__(self, left, right):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   605
        lterm = TerminalExpression(None, left)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   606
        rterm = TerminalExpression(None, right)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   607
        EqualExpression.__init__(self, None, lterm, rterm)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   608
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   609
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   610
# in format KEY : OPERATOR CLASS
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   611
OPERATORS = {
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   612
    'and' : AndExpression,
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   613
    'nand' : NandExpression,
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   614
    'or' : OrExpression,
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   615
    'xor' : XorExpression,
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   616
    'nor' : NorExpression,
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   617
    'not' : NotExpression,
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   618
    'truth' : TruthExpression,
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   619
    '==' : EqualExpression,
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   620
    '!=' : NotEqualExpression,
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   621
    '<' : LessThanExpression,
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   622
    '>' : GreaterThanExpression,
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   623
    '<=' : LessThanEqualExpression,
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   624
    '>=' : GreaterThanEqualExpression,
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   625
    'requires' : RequireExpression,
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   626
    'excludes' : ExcludeExpression,
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   627
    '-' : NegExpression
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   628
    }
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   629
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   630
def add_operator(key, operator_class=None, baseclass=RequireExpression):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   631
    """
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   632
    Add new operator key and operator class.
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   633
    If operator class isn't provided the baseclass parameter is used as
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   634
    operator base. The baseclass parameter is RequireExpression by default
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   635
    which has success condition left_rule=True and right_rule=True
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   636
    
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   637
    """
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   638
    OPERATORS[key] = operator_class or create_new_class(key, baseclass)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   639
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   640
def create_new_class(key, baseclass):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   641
    ns = baseclass.__dict__.copy()
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   642
    ns['KEY'] = key
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   643
    key_pieces = key.split('_')
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   644
    class_prefix = ''.join([key_piece.capitalize() for key_piece in key_pieces])
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   645
    new_class = type(class_prefix + 'Expression', (baseclass,), ns)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   646
    return new_class
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   647
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   648
class ParseException(Exception): pass
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   649
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   650
class ASTInterpreter(object):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   651
    def __init__(self, infix_expression=None, context=None):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   652
        """ Takes infix expression as string """
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   653
        self.context = context or DefaultContext(None)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   654
        # logger.debug("AST init context: %s" % self.context)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   655
        self._init_locals(infix_expression)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   656
        if infix_expression:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   657
            self.create_ast()
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   658
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   659
    def _init_locals(self, infix_expression):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   660
        # The result value of full eval of the parse_tree
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   661
        self.value = None
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   662
        self.warnings = {}
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   663
        self.errors = {}
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   664
        self.postfix_array = []
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   665
        self.parse_tree = []
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   666
        self.expression = infix_expression
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   667
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   668
    def __unicode__(self):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   669
        s = ''
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   670
        for expr in self.parse_tree:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   671
            s += unicode(expr)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   672
        return s
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   673
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   674
    def add_error(self, key, error_dict):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   675
        if self.errors.has_key(key):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   676
            self.errors[key].append(error_dict)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   677
        else:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   678
            self.errors[key] = [error_dict]
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   679
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   680
    def create_ast(self, infix_expression=None):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   681
        if infix_expression:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   682
            self._init_locals(infix_expression)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   683
        self._infix_to_postfix()
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   684
        self._create_parse_tree()
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   685
        return self.parse_tree
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   686
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   687
    def _infix_to_postfix(self):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   688
        """
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   689
        Shunting yard algorithm used to convert infix presentation to postfix.
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   690
        """
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   691
        if not self.expression:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   692
            raise ParseException('Expression is None')
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   693
        tokens = get_tokens(self.expression) # [token for token in self.expression.split()]
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   694
        stack = []
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   695
        # logger.debug('TOKENS: %s' % tokens)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   696
        for token in tokens:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   697
            # logger.debug('TOKEN: %s' % token)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   698
            if token.lower() in OPERATORS:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   699
                op_class = OPERATORS.get(token)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   700
                if stack:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   701
                    while len(stack) != 0:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   702
                        top = stack[-1]
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   703
                        if top in OPERATORS:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   704
                            top_operator = OPERATORS.get(top)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   705
                            if op_class.PRECEDENCE <= top_operator.PRECEDENCE:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   706
                                self.postfix_array.append(stack.pop())
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   707
                            else:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   708
                                # Break from loop if top operator precedence is less.
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   709
                                break
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   710
                        else:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   711
                            # If top not operator break from loop
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   712
                            break
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   713
                stack.append(token)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   714
            elif token == LEFT_PARENTHESIS:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   715
                # logger.debug('Left parenthesis')
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   716
                stack.append(token)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   717
            elif token == RIGHT_PARENTHESIS:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   718
                # logger.debug('Right parenthesis')
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   719
                left_par_found = False
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   720
                stack_token = stack.pop()
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   721
                while stack_token:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   722
                    if stack_token != LEFT_PARENTHESIS:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   723
                        self.postfix_array.append(stack_token)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   724
                    else:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   725
                        left_par_found = True
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   726
                        break
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   727
                    if stack:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   728
                        stack_token = stack.pop()
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   729
                    else:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   730
                        stack_token = None
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   731
                        
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   732
                if not left_par_found:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   733
                    raise ParseException('Mismatched parenthesis "%s".' % LEFT_PARENTHESIS)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   734
            else:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   735
                # logger.debug('Adding value to output. %s' % repr((token)))
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   736
                self.postfix_array.append((token))
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   737
            
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   738
        # There should be only operators left in the stack
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   739
        if stack:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   740
            # logger.debug('Operators in stack.')
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   741
            operator = stack.pop()
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   742
            while operator:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   743
                if operator != LEFT_PARENTHESIS:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   744
                    self.postfix_array.append(operator)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   745
                else:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   746
                    raise ParseException('Mismatched parenthesis "%s".' % LEFT_PARENTHESIS)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   747
                if stack:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   748
                    operator = stack.pop()
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   749
                else:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   750
                    operator = None
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   751
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   752
        # logger.debug('Infix to postfix conversion: %s' % self.postfix_array)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   753
        return self.postfix_array
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   754
    
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   755
    def _create_parse_tree(self):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   756
        self.parse_tree = []
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   757
        for token in self.postfix_array:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   758
            if token in OPERATORS:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   759
                # logger.debug('OP: %s' % (token))
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   760
                expression_class = OPERATORS[token]
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   761
                params = []
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   762
                for i in range(expression_class.PARAM_COUNT):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   763
                    try:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   764
                        params.append(self.parse_tree.pop())
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   765
                    except IndexError, e:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   766
                        raise ParseException('Syntax error: "%s"' % self.expression)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   767
                params.reverse()
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   768
                expression = expression_class(self, *params)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   769
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   770
                # logger.debug('The operation: %s' % expression)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   771
                self.parse_tree.append(expression)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   772
            else:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   773
                expression = TerminalExpression(self, token)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   774
                self.parse_tree.append(expression)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   775
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   776
        #logger.debug('THE STACK: %s' % self.parse_tree)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   777
        #for s in self.parse_tree:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   778
        #    logger.debug('Stack e: %s' % str(s))
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   779
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   780
        return self.parse_tree
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   781
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   782
    def eval(self, context=None, **kwargs):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   783
        """ Evals the AST
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   784
        If empty expression is given, None is returned
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   785
        """
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   786
        for expression in self.parse_tree:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   787
            self.value = expression.eval(context, **kwargs)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   788
        return self.value
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   789
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   790
    @staticmethod
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   791
    def extract_refs(expression):
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   792
        tokens = get_tokens(expression)
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   793
        refs = []
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   794
        for token in tokens:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   795
            if not token.lower() in OPERATORS and token != LEFT_PARENTHESIS and token != RIGHT_PARENTHESIS:
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   796
                refs.append(token.strip('%s%s' % (LEFT_PARENTHESIS, RIGHT_PARENTHESIS)))
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   797
        return refs
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   798
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   799
##################################################################
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   800
# Create and configure the main level logger
e7e0ae78773e ConE 1.2.11 release
m2lahtel
parents:
diff changeset
   801
logger = logging.getLogger('cone')